<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.2.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/32x32-paimeng.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/16x16-paimeng.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/all.min.css" integrity="sha256-xejo6yLi6vGtAjcMIsY8BHdKsLg7QynVlFMzdQgUuy8=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/themes/blue/pace-theme-minimal.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/pace.min.js" integrity="sha256-gqd7YTjg/BtfqWSwsJOvndl0Bxc8gFImLEkXQT8+qj0=" crossorigin="anonymous"></script>

<script class="next-config" data-name="main" type="application/json">{"hostname":"xuande-hk.gitee.io","root":"/","images":"/images","scheme":"Pisces","darkmode":false,"version":"8.12.3","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":true,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"shrinkIn"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="本菜鸟的Go语言学习笔记，历时1个月，包含了Go语言大部分的基本语法（不敢说全部）">
<meta property="og:type" content="article">
<meta property="og:title" content="《golong入门教程📚》，从零开始入门❤️（建议收藏⭐️）">
<meta property="og:url" content="https://xuande-hk.gitee.io/posts/5.html">
<meta property="og:site_name" content="玄德の博客">
<meta property="og:description" content="本菜鸟的Go语言学习笔记，历时1个月，包含了Go语言大部分的基本语法（不敢说全部）">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://xuande-1309318075.cos.ap-beijing.myqcloud.com/my-blog-image/go-post.jpg">
<meta property="article:published_time" content="2023-03-22T04:00:00.000Z">
<meta property="article:modified_time" content="2023-03-22T06:34:21.219Z">
<meta property="article:author" content="玄德">
<meta property="article:tag" content="Go">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://xuande-1309318075.cos.ap-beijing.myqcloud.com/my-blog-image/go-post.jpg">


<link rel="canonical" href="https://xuande-hk.gitee.io/posts/5.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://xuande-hk.gitee.io/posts/5.html","path":"/posts/5.html","title":"《golong入门教程📚》，从零开始入门❤️（建议收藏⭐️）"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>《golong入门教程📚》，从零开始入门❤️（建议收藏⭐️） | 玄德の博客</title>
  





  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">

  <!-- 看板娘 -->
  
      <script async src="/live2d/autoload.js"></script>
      <!-- <script async src="https://fastly.jsdelivr.net/gh/xuande-hk/live2d-widget/autoload.js"></script> -->
  
  
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">玄德の博客</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">不说话 装高手</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</div>
        
  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Go%E8%AF%AD%E8%A8%80%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0"><span class="nav-number">1.</span> <span class="nav-text">Go语言学习笔记</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95"><span class="nav-number">2.</span> <span class="nav-text">基本语法</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%B3%A8%E9%87%8A"><span class="nav-number">2.1.</span> <span class="nav-text">注释</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%98%E9%87%8F"><span class="nav-number">2.2.</span> <span class="nav-text">变量</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%98%E9%87%8F%E7%9A%84%E5%A3%B0%E6%98%8E"><span class="nav-number">2.2.1.</span> <span class="nav-text">变量的声明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%98%E9%87%8F%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96"><span class="nav-number">2.2.2.</span> <span class="nav-text">变量的初始化</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%98%E9%87%8F%E7%9A%84%E4%BA%A4%E6%8D%A2"><span class="nav-number">2.2.3.</span> <span class="nav-text">变量的交换</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8C%BF%E5%90%8D%E5%8F%98%E9%87%8F"><span class="nav-number">2.2.4.</span> <span class="nav-text">匿名变量</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%98%E9%87%8F%E7%9A%84%E4%BD%9C%E7%94%A8%E5%9F%9F"><span class="nav-number">2.2.5.</span> <span class="nav-text">变量的作用域</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%B8%B8%E9%87%8F"><span class="nav-number">2.2.6.</span> <span class="nav-text">常量</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.3.</span> <span class="nav-text">基本数据类型</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%B8%83%E5%B0%94%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.3.1.</span> <span class="nav-text">布尔类型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%95%B0%E5%AD%97%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.3.2.</span> <span class="nav-text">数字类型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AD%97%E7%AC%A6%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.3.3.</span> <span class="nav-text">字符类型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8C%87%E9%92%88%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.3.4.</span> <span class="nav-text">指针类型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2"><span class="nav-number">2.3.5.</span> <span class="nav-text">数据类型转换</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="nav-number">2.4.</span> <span class="nav-text">运算符</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%AE%97%E6%9C%AF%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="nav-number">2.4.1.</span> <span class="nav-text">算术运算符</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%85%B3%E7%B3%BB%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="nav-number">2.4.2.</span> <span class="nav-text">关系运算符</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%80%BB%E8%BE%91%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="nav-number">2.4.3.</span> <span class="nav-text">逻辑运算符</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%8D%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="nav-number">2.4.4.</span> <span class="nav-text">位运算符</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%B5%8B%E5%80%BC%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="nav-number">2.4.5.</span> <span class="nav-text">赋值运算符</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%85%B6%E4%BB%96%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="nav-number">2.4.6.</span> <span class="nav-text">其他运算符</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8C%87%E9%92%88"><span class="nav-number">2.5.</span> <span class="nav-text">指针</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6"><span class="nav-number">3.</span> <span class="nav-text">流程控制</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%80%89%E6%8B%A9%E7%BB%93%E6%9E%84"><span class="nav-number">3.1.</span> <span class="nav-text">选择结构</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#if%E8%AF%AD%E5%8F%A5"><span class="nav-number">3.1.1.</span> <span class="nav-text">if语句</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#switch%E8%AF%AD%E5%8F%A5"><span class="nav-number">3.1.2.</span> <span class="nav-text">switch语句</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%BE%AA%E7%8E%AF%E7%BB%93%E6%9E%84"><span class="nav-number">3.2.</span> <span class="nav-text">循环结构</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#for%E8%AF%AD%E5%8F%A5"><span class="nav-number">3.2.1.</span> <span class="nav-text">for语句</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#break"><span class="nav-number">3.2.2.</span> <span class="nav-text">break</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%94%AE%E5%80%BC%E5%BE%AA%E7%8E%AF"><span class="nav-number">3.2.3.</span> <span class="nav-text">键值循环</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%A1%88%E4%BE%8B"><span class="nav-number">3.2.4.</span> <span class="nav-text">案例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%87%BD%E6%95%B0"><span class="nav-number">4.</span> <span class="nav-text">函数</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%87%BD%E6%95%B0%E7%9A%84%E5%A3%B0%E6%98%8E"><span class="nav-number">4.1.</span> <span class="nav-text">函数的声明</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%86%85%E7%BD%AE%E5%87%BD%E6%95%B0"><span class="nav-number">4.2.</span> <span class="nav-text">内置函数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AF%E5%8F%98%E5%8F%82%E6%95%B0"><span class="nav-number">4.3.</span> <span class="nav-text">可变参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%82%E6%95%B0%E4%BC%A0%E9%80%92"><span class="nav-number">4.4.</span> <span class="nav-text">参数传递</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%80%92%E5%BD%92%E5%87%BD%E6%95%B0"><span class="nav-number">4.5.</span> <span class="nav-text">递归函数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%87%BD%E6%95%B0%E5%8F%98%E9%87%8F"><span class="nav-number">4.6.</span> <span class="nav-text">函数变量</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0"><span class="nav-number">4.7.</span> <span class="nav-text">匿名函数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#defer"><span class="nav-number">4.8.</span> <span class="nav-text">defer</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%97%AD%E5%8C%85"><span class="nav-number">4.9.</span> <span class="nav-text">闭包</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%AE%B9%E5%99%A8"><span class="nav-number">5.</span> <span class="nav-text">容器</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%95%B0%E7%BB%84%EF%BC%88array%EF%BC%89"><span class="nav-number">5.1.</span> <span class="nav-text">数组（array）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%95%B0%E7%BB%84%E7%9A%84%E5%AE%9A%E4%B9%89"><span class="nav-number">5.1.1.</span> <span class="nav-text">数组的定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%A4%9A%E7%BB%B4%E6%95%B0%E7%BB%84"><span class="nav-number">5.1.2.</span> <span class="nav-text">多维数组</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%88%87%E7%89%87%EF%BC%88slice%EF%BC%89"><span class="nav-number">5.2.</span> <span class="nav-text">切片（slice）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%88%87%E7%89%87%E7%9A%84%E5%AE%9A%E4%B9%89"><span class="nav-number">5.2.1.</span> <span class="nav-text">切片的定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%BF%BD%E5%8A%A0%E5%87%BD%E6%95%B0"><span class="nav-number">5.2.2.</span> <span class="nav-text">追加函数</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%88%97%E8%A1%A8%EF%BC%88list%EF%BC%89"><span class="nav-number">5.3.</span> <span class="nav-text">列表（list）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%88%97%E8%A1%A8%E7%9A%84%E5%AE%9A%E4%B9%89"><span class="nav-number">5.3.1.</span> <span class="nav-text">列表的定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BB%8E%E5%88%97%E8%A1%A8%E4%B8%AD%E5%88%A0%E9%99%A4%E5%85%83%E7%B4%A0"><span class="nav-number">5.3.2.</span> <span class="nav-text">从列表中删除元素</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%98%A0%E5%B0%84%EF%BC%88map%EF%BC%89"><span class="nav-number">5.4.</span> <span class="nav-text">映射（map）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%98%A0%E5%B0%84%E7%9A%84%E5%AE%9A%E4%B9%89"><span class="nav-number">5.4.1.</span> <span class="nav-text">映射的定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#map%E7%9A%84%E5%AE%B9%E9%87%8F"><span class="nav-number">5.4.2.</span> <span class="nav-text">map的容量</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%93%8D%E4%BD%9Cmap"><span class="nav-number">5.4.3.</span> <span class="nav-text">操作map</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1"><span class="nav-number">6.</span> <span class="nav-text">面向对象</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%93%E6%9E%84%E4%BD%93"><span class="nav-number">6.1.</span> <span class="nav-text">结构体</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%93%E6%9E%84%E4%BD%93%E5%AE%9A%E4%B9%89"><span class="nav-number">6.1.1.</span> <span class="nav-text">结构体定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%93%E6%9E%84%E4%BD%93%E5%AE%9E%E4%BE%8B"><span class="nav-number">6.1.2.</span> <span class="nav-text">结构体实例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%93%E6%9E%84%E4%BD%93%E4%B9%8B%E9%97%B4%E7%9A%84%E8%BD%AC%E6%8D%A2"><span class="nav-number">6.1.3.</span> <span class="nav-text">结构体之间的转换</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%96%B9%E6%B3%95"><span class="nav-number">6.2.</span> <span class="nav-text">方法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%96%B9%E6%B3%95%E7%9A%84%E5%AE%9A%E4%B9%89"><span class="nav-number">6.2.1.</span> <span class="nav-text">方法的定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B%E6%96%B9%E6%B3%95"><span class="nav-number">6.2.2.</span> <span class="nav-text">自定义类型方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%96%B9%E6%B3%95%E5%92%8C%E5%87%BD%E6%95%B0%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">6.2.3.</span> <span class="nav-text">方法和函数的区别</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B0%81%E8%A3%85"><span class="nav-number">6.3.</span> <span class="nav-text">封装</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%B0%81%E8%A3%85%E7%9A%84%E5%AE%9A%E4%B9%89"><span class="nav-number">6.3.1.</span> <span class="nav-text">封装的定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AE%9E%E7%8E%B0%E5%B0%81%E8%A3%85"><span class="nav-number">6.3.2.</span> <span class="nav-text">实现封装</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF"><span class="nav-number">6.4.</span> <span class="nav-text">继承</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF%E7%9A%84%E5%AE%9A%E4%B9%89"><span class="nav-number">6.4.1.</span> <span class="nav-text">继承的定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="nav-number">6.4.2.</span> <span class="nav-text">继承的实现</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF%E7%9A%84%E7%89%B9%E6%80%A7"><span class="nav-number">6.4.3.</span> <span class="nav-text">继承的特性</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8E%A5%E5%8F%A3"><span class="nav-number">6.5.</span> <span class="nav-text">接口</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%A3%B0%E6%98%8E"><span class="nav-number">6.5.1.</span> <span class="nav-text">接口的声明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%89%B9%E6%80%A7"><span class="nav-number">6.5.2.</span> <span class="nav-text">接口的特性</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%A4%9A%E6%80%81"><span class="nav-number">6.5.3.</span> <span class="nav-text">多态</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%96%AD%E8%A8%80"><span class="nav-number">6.5.4.</span> <span class="nav-text">断言</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%B9%B6%E5%8F%91"><span class="nav-number">7.</span> <span class="nav-text">并发</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8D%8F%E7%A8%8B"><span class="nav-number">7.1.</span> <span class="nav-text">协程</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%AE%A4%E8%AF%86%E5%8D%8F%E7%A8%8B"><span class="nav-number">7.1.1.</span> <span class="nav-text">认识协程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8D%8F%E7%A8%8B%E7%9A%84%E5%BC%80%E5%90%AF"><span class="nav-number">7.1.2.</span> <span class="nav-text">协程的开启</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#WaitGroup"><span class="nav-number">7.1.3.</span> <span class="nav-text">WaitGroup</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BA%92%E6%96%A5%E9%94%81"><span class="nav-number">7.1.4.</span> <span class="nav-text">互斥锁</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%AF%BB%E5%86%99%E9%94%81"><span class="nav-number">7.1.5.</span> <span class="nav-text">读写锁</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8D%95%E8%8E%B7%E9%94%99%E8%AF%AF"><span class="nav-number">7.1.6.</span> <span class="nav-text">捕获错误</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AE%A1%E9%81%93"><span class="nav-number">7.2.</span> <span class="nav-text">管道</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%AE%A1%E9%81%93%E5%85%A5%E9%97%A8"><span class="nav-number">7.2.1.</span> <span class="nav-text">管道入门</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8D%95%E5%90%91%E7%AE%A1%E9%81%93"><span class="nav-number">7.2.2.</span> <span class="nav-text">单向管道</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#select"><span class="nav-number">7.2.3.</span> <span class="nav-text">select</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B"><span class="nav-number">7.3.</span> <span class="nav-text">并发编程</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8D%8F%E7%A8%8B%E4%B8%8E%E7%AE%A1%E9%81%93"><span class="nav-number">7.3.1.</span> <span class="nav-text">协程与管道</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%93%8D%E4%BD%9C%E5%90%8C%E4%B8%80%E4%B8%AA%E7%AE%A1%E9%81%93"><span class="nav-number">7.3.1.1.</span> <span class="nav-text">操作同一个管道</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%B1%82%E7%B4%A0%E6%95%B0"><span class="nav-number">7.3.1.2.</span> <span class="nav-text">求素数</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85"><span class="nav-number">7.3.2.</span> <span class="nav-text">生产者消费者</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B"><span class="nav-number">7.4.</span> <span class="nav-text">网络编程</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%AE%80%E5%8D%95%E7%9A%84Web%E6%9C%8D%E5%8A%A1%E5%99%A8"><span class="nav-number">7.4.1.</span> <span class="nav-text">简单的Web服务器</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#TCP%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%E9%80%9A%E4%BF%A1"><span class="nav-number">7.4.2.</span> <span class="nav-text">TCP网络协议通信</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%8F%8D%E5%B0%84"><span class="nav-number">8.</span> <span class="nav-text">反射</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BA%86%E8%A7%A3%E5%8F%8D%E5%B0%84"><span class="nav-number">8.1.</span> <span class="nav-text">了解反射</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%8D%E5%B0%84%E7%9A%84%E7%B1%BB%E5%9E%8B"><span class="nav-number">8.2.</span> <span class="nav-text">反射的类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%8D%E5%B0%84%E7%9A%84%E7%A7%8D%E7%B1%BB"><span class="nav-number">8.3.</span> <span class="nav-text">反射的种类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%8D%E5%B0%84%E7%9A%84%E6%93%8D%E4%BD%9C"><span class="nav-number">8.4.</span> <span class="nav-text">反射的操作</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E6%96%87%E4%BB%B6%E5%A4%84%E7%90%86"><span class="nav-number">9.</span> <span class="nav-text">文件处理</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6"><span class="nav-number">9.1.</span> <span class="nav-text">文本文件</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%86%99%E5%9C%A8%E6%9C%80%E5%90%8E"><span class="nav-number">10.</span> <span class="nav-text">写在最后</span></a></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="玄德"
      src="/images/avatar.png">
  <p class="site-author-name" itemprop="name">玄德</p>
  <div class="site-description" itemprop="description">像珍惜礼物一样，珍惜今天。</div>
</div>
<div class="site-state-wrap site-overview-item animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">5</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
        <span class="site-state-item-count">2</span>
        <span class="site-state-item-name">分类</span>
      </div>
      <div class="site-state-item site-state-tags">
        <span class="site-state-item-count">4</span>
        <span class="site-state-item-name">标签</span>
      </div>
  </nav>
</div>
  <div class="links-of-author site-overview-item animated">
      <span class="links-of-author-item">
        <a href="https://github.com/yourname" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;yourname" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:yourname@gmail.com" title="E-Mail → mailto:yourname@gmail.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://space.bilibili.com/286727058" title="bilibili → https:&#x2F;&#x2F;space.bilibili.com&#x2F;286727058" rel="noopener" target="_blank"><i class="custom bilibili fa-fw"></i>bilibili</a>
      </span>
  </div>


  <div class="links-of-blogroll site-overview-item animated">
    <div class="links-of-blogroll-title"><i class="fa fa-globe fa-fw"></i>
      友情链接
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="https://fanyi.baidu.com/?aldtype=16047#it/zh/onmobile" title="https:&#x2F;&#x2F;fanyi.baidu.com&#x2F;?aldtype&#x3D;16047#it&#x2F;zh&#x2F;onmobile" rel="noopener" target="_blank">百度翻译</a>
        </li>
    </ul>
  </div>

        </div>
      </div>

      <!-- 自定义配置文件 -->
      <!-- 近期文章板块 -->
      
        <div class="links-of-blogroll motion-element links-of-blogroll-block">
          <div class="links-of-blogroll-title">
            <!-- modify icon to fire by szw -->
            <i class="fa fa-history fa-" aria-hidden="true"></i>
            近期文章
          </div>
          <ul class="links-of-blogroll-list">
            
            
            <li>
              <a href="/" title="" target="_blank"></a>
            </li>
            
            <li>
              <a href="/" title="" target="_blank"></a>
            </li>
            
            <li>
              <a href="/" title="" target="_blank"></a>
            </li>
            
            <li>
              <a href="/" title="" target="_blank"></a>
            </li>
            
            <li>
              <a href="/" title="" target="_blank"></a>
            </li>
            
          </ul>
        </div>
      

      <!-- canvas粒子时钟 -->
        
        <!-- canvas粒子时钟 https://www.cnblogs.com/xiaohuochai/p/6368039.html
  https://www.html5tricks.com/html5-canvas-dance-time.html
 -->
<div id="">
  <canvas id="canvas" style="width:60%;">
</div>
<script async>
(function(){
  var WINDOW_WIDTH = 820;
  		var WINDOW_HEIGHT = 250;
  		var RADIUS = 7; //球半径
  		var NUMBER_GAP = 10; //数字之间的间隙
  		var u=0.65; //碰撞能量损耗系数
  		var context; //Canvas绘制上下文
  		var balls = []; //存储彩色的小球
  		const colors = ["#33B5E5","#0099CC","#AA66CC","#9933CC","#99CC00","#669900","#FFBB33","#FF8800","#FF4444","#CC0000"]; //彩色小球的颜色
  		var currentNums = []; //屏幕显示的8个字符
  		var digit =
                  [
                      [
                          [0,0,1,1,1,0,0],
                          [0,1,1,0,1,1,0],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [0,1,1,0,1,1,0],
                          [0,0,1,1,1,0,0]
                      ],//0
                      [
                          [0,0,0,1,1,0,0],
                          [0,1,1,1,1,0,0],
                          [0,0,0,1,1,0,0],
                          [0,0,0,1,1,0,0],
                          [0,0,0,1,1,0,0],
                          [0,0,0,1,1,0,0],
                          [0,0,0,1,1,0,0],
                          [0,0,0,1,1,0,0],
                          [0,0,0,1,1,0,0],
                          [1,1,1,1,1,1,1]
                      ],//1
                      [
                          [0,1,1,1,1,1,0],
                          [1,1,0,0,0,1,1],
                          [0,0,0,0,0,1,1],
                          [0,0,0,0,1,1,0],
                          [0,0,0,1,1,0,0],
                          [0,0,1,1,0,0,0],
                          [0,1,1,0,0,0,0],
                          [1,1,0,0,0,0,0],
                          [1,1,0,0,0,1,1],
                          [1,1,1,1,1,1,1]
                      ],//2
                      [
                          [1,1,1,1,1,1,1],
                          [0,0,0,0,0,1,1],
                          [0,0,0,0,1,1,0],
                          [0,0,0,1,1,0,0],
                          [0,0,1,1,1,0,0],
                          [0,0,0,0,1,1,0],
                          [0,0,0,0,0,1,1],
                          [0,0,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [0,1,1,1,1,1,0]
                      ],//3
                      [
                          [0,0,0,0,1,1,0],
                          [0,0,0,1,1,1,0],
                          [0,0,1,1,1,1,0],
                          [0,1,1,0,1,1,0],
                          [1,1,0,0,1,1,0],
                          [1,1,1,1,1,1,1],
                          [0,0,0,0,1,1,0],
                          [0,0,0,0,1,1,0],
                          [0,0,0,0,1,1,0],
                          [0,0,0,1,1,1,1]
                      ],//4
                      [
                          [1,1,1,1,1,1,1],
                          [1,1,0,0,0,0,0],
                          [1,1,0,0,0,0,0],
                          [1,1,1,1,1,1,0],
                          [0,0,0,0,0,1,1],
                          [0,0,0,0,0,1,1],
                          [0,0,0,0,0,1,1],
                          [0,0,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [0,1,1,1,1,1,0]
                      ],//5
                      [
                          [0,0,0,0,1,1,0],
                          [0,0,1,1,0,0,0],
                          [0,1,1,0,0,0,0],
                          [1,1,0,0,0,0,0],
                          [1,1,0,1,1,1,0],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [0,1,1,1,1,1,0]
                      ],//6
                      [
                          [1,1,1,1,1,1,1],
                          [1,1,0,0,0,1,1],
                          [0,0,0,0,1,1,0],
                          [0,0,0,0,1,1,0],
                          [0,0,0,1,1,0,0],
                          [0,0,0,1,1,0,0],
                          [0,0,1,1,0,0,0],
                          [0,0,1,1,0,0,0],
                          [0,0,1,1,0,0,0],
                          [0,0,1,1,0,0,0]
                      ],//7
                      [
                          [0,1,1,1,1,1,0],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [0,1,1,1,1,1,0],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [0,1,1,1,1,1,0]
                      ],//8
                      [
                          [0,1,1,1,1,1,0],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [1,1,0,0,0,1,1],
                          [0,1,1,1,0,1,1],
                          [0,0,0,0,0,1,1],
                          [0,0,0,0,0,1,1],
                          [0,0,0,0,1,1,0],
                          [0,0,0,1,1,0,0],
                          [0,1,1,0,0,0,0]
                      ],//9
                      [
                          [0,0,0,0],
                          [0,0,0,0],
                          [0,1,1,0],
                          [0,1,1,0],
                          [0,0,0,0],
                          [0,0,0,0],
                          [0,1,1,0],
                          [0,1,1,0],
                          [0,0,0,0],
                          [0,0,0,0]
                      ]//:
                  ];

  		function drawDatetime(cxt){
  			var nums = [];

  			context.fillStyle="#005eac"
  			var date = new Date();
  			var offsetX = 70, offsetY = 30;
  			var hours = date.getHours();
  			var num1 = Math.floor(hours/10);
  			var num2 = hours%10;
  			nums.push({num: num1});
  			nums.push({num: num2});
  			nums.push({num: 10}); //冒号
  			var minutes = date.getMinutes();
  			var num1 = Math.floor(minutes/10);
  			var num2 = minutes%10;
  			nums.push({num: num1});
  			nums.push({num: num2});
  			nums.push({num: 10}); //冒号
  			var seconds = date.getSeconds();
  			var num1 = Math.floor(seconds/10);
  			var num2 = seconds%10;
  			nums.push({num: num1});
  			nums.push({num: num2});

  			for(var x = 0;x<nums.length;x++){
  				nums[x].offsetX = offsetX;
  				offsetX = drawSingleNumber(offsetX,offsetY, nums[x].num,cxt);
  				//两个数字连一块，应该间隔一些距离
  				if(x<nums.length-1){
  					if((nums[x].num!=10) &&(nums[x+1].num!=10)){
  						offsetX+=NUMBER_GAP;
  					}
  				}
  			}

  			//说明这是初始化
  			if(currentNums.length ==0){
  				currentNums = nums;
  			}else{
  				//进行比较
  				for(var index = 0;index<currentNums.length;index++){
  					if(currentNums[index].num!=nums[index].num){
  						//不一样时，添加彩色小球
  						addBalls(nums[index]);
  						currentNums[index].num=nums[index].num;
  					}
  				}
  			}
  			renderBalls(cxt);
  			updateBalls();

  			return date;
  		}

  		function addBalls (item) {
  			var num = item.num;
  			var numMatrix = digit[num];
  			for(var y = 0;y<numMatrix.length;y++){
  				for(var x = 0;x<numMatrix[y].length;x++){
  					if(numMatrix[y][x]==1){
  						var ball={
  							offsetX:item.offsetX+RADIUS+RADIUS*2*x,
  							offsetY:30+RADIUS+RADIUS*2*y,
  							color:colors[Math.floor(Math.random()*colors.length)],
  							g:1.5+Math.random(),
  							vx:Math.pow(-1, Math.ceil(Math.random()*10))*4+Math.random(),
  							vy:-5
  						}
  						balls.push(ball);
  					}
  				}
  			}
  		}

  		function renderBalls(cxt){
  			for(var index = 0;index<balls.length;index++){
  				cxt.beginPath();
  				cxt.fillStyle=balls[index].color;
  				cxt.arc(balls[index].offsetX, balls[index].offsetY, RADIUS, 0, 2*Math.PI);
  				cxt.fill();
  			}
  		}

  		function updateBalls () {
  			var i =0;
  			for(var index = 0;index<balls.length;index++){
  				var ball = balls[index];
  				ball.offsetX += ball.vx;
  				ball.offsetY += ball.vy;
  				ball.vy+=ball.g;
  				if(ball.offsetY > (WINDOW_HEIGHT-RADIUS)){
  					ball.offsetY= WINDOW_HEIGHT-RADIUS;
  					ball.vy=-ball.vy*u;
  				}
  				if(ball.offsetX>RADIUS&&ball.offsetX<(WINDOW_WIDTH-RADIUS)){

  					balls[i]=balls[index];
  					i++;
  				}
  			}
  			//去除出边界的球
  			for(;i<balls.length;i++){
  				balls.pop();
  			}
  		}
  		function drawSingleNumber(offsetX, offsetY, num, cxt){
  			var numMatrix = digit[num];
  			for(var y = 0;y<numMatrix.length;y++){
  				for(var x = 0;x<numMatrix[y].length;x++){
  					if(numMatrix[y][x]==1){
  						cxt.beginPath();
  						cxt.arc(offsetX+RADIUS+RADIUS*2*x,offsetY+RADIUS+RADIUS*2*y,RADIUS,0,2*Math.PI);
  						cxt.fill();
  					}
  				}
  			}
  			cxt.beginPath();
  			offsetX += numMatrix[0].length*RADIUS*2;
  			return offsetX;
  		}

  		var canvas = document.getElementById("canvas");
  		canvas.width=WINDOW_WIDTH;
  		canvas.height=WINDOW_HEIGHT;
  		context = canvas.getContext("2d");

  		//记录当前绘制的时刻
  		var currentDate = new Date();

  		setInterval(function(){
  			//清空整个Canvas，重新绘制内容
  			context.clearRect(0, 0, context.canvas.width, context.canvas.height);
  			drawDatetime(context);
  		}, 50)
})();
</script>

      

      <!-- 网站运行时间 -->
           
        <div id="days"></div>

<script async language="javascript">

  function show_date_time(){
      window.setTimeout("show_date_time()", 1000);
  //    BirthDay=new Date("25/07/2022 12:00:00");
      BirthDay=new Date("07/25/2022 12:00:00");
      today=new Date();
      timeold=(today.getTime()-BirthDay.getTime());
      sectimeold=timeold/1000
      secondsold=Math.floor(sectimeold);
      msPerDay=24*60*60*1000
      e_daysold=timeold/msPerDay
      daysold=Math.floor(e_daysold);
      e_hrsold=(e_daysold-daysold)*24;
      hrsold=setzero(Math.floor(e_hrsold));
      e_minsold=(e_hrsold-hrsold)*60;
      minsold=setzero(Math.floor((e_hrsold-hrsold)*60));
      seconds=setzero(Math.floor((e_minsold-minsold)*60));
      document.getElementById('days').innerHTML="已运行"+daysold+"天"+hrsold+"时"+minsold+"分"+seconds+"秒";
  }

  function setzero(i){
      if (i<10)
      {i="0" + i};
      return i;
  }

  show_date_time();

</script>

      

    </div>
  </aside>
  <div class="sidebar-dimmer"></div>


    </header>

    
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

  <a href="https://github.com/XuanDe-HK" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


    <div class="main-inner post posts-expand">


  


<div class="post-block">
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://xuande-hk.gitee.io/posts/5.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="玄德">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="玄德の博客">
      <meta itemprop="description" content="像珍惜礼物一样，珍惜今天。">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="《golong入门教程📚》，从零开始入门❤️（建议收藏⭐️） | 玄德の博客">
      <meta itemprop="description" content="本菜鸟的Go语言学习笔记，历时1个月，包含了Go语言大部分的基本语法（不敢说全部）">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          《golong入门教程📚》，从零开始入门❤️（建议收藏⭐️）
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>
      

      <time title="创建时间：2023-03-22 12:00:00 / 修改时间：14:34:21" itemprop="dateCreated datePublished" datetime="2023-03-22T12:00:00+08:00">2023-03-22</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E7%AC%94%E8%AE%B0/" itemprop="url" rel="index"><span itemprop="name">笔记</span></a>
        </span>
    </span>

  
    <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv">
      <span class="post-meta-item-icon">
        <i class="far fa-eye"></i>
      </span>
      <span class="post-meta-item-text">阅读次数：</span>
      <span id="busuanzi_value_page_pv"></span>
    </span>
</div>

            <div class="post-description">本菜鸟的Go语言学习笔记，历时1个月，包含了Go语言大部分的基本语法（不敢说全部）</div>
        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      <div class="post-gallery" itemscope itemtype="http://schema.org/ImageGallery">
    
    <div class="post-gallery-image">
      <img src="https://xuande-1309318075.cos.ap-beijing.myqcloud.com/my-blog-image/go-post.jpg" itemprop="contentUrl">
    </div>
    </div>
        <h1 id="Go语言学习笔记"><a href="#Go语言学习笔记" class="headerlink" title="Go语言学习笔记"></a>Go语言学习笔记</h1><p>本菜鸟的Go语言学习笔记，历时1个月，包含了Go语言大部分的基本语法（不敢说全部），学习期间参考了各种视频，阅读了各种文章，主要参考名单如下：</p>
<p><a href="#%E5%86%99%E5%9C%A8%E6%9C%80%E5%90%8E">点击跳转到参考名单&lt;（￣︶￣）&gt;</a></p>
<p>在这里小声说两句：Go语言对于并发的支持非常nice，在现在这个卷的时代，多学习一门编程语言，就多一点竞争力，Go语言还是我比较推荐学习的一门编程语言</p>
<p><strong>文章目录</strong></p>
<ol>
<li><a href="#%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95">基本语法</a></li>
<li><a href="#%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6">流程控制</a></li>
<li><a href="#%E5%87%BD%E6%95%B0">函数</a></li>
<li><a href="#%E5%AE%B9%E5%99%A8">容器</a></li>
<li><a href="#%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1">面向对象</a></li>
<li><a href="#%E5%B9%B6%E5%8F%91">并发</a></li>
<li><a href="#%E5%8F%8D%E5%B0%84">反射</a></li>
<li><a href="#%E6%96%87%E4%BB%B6%E5%A4%84%E7%90%86">文件处理</a></li>
</ol>
<h1 id="基本语法"><a href="#基本语法" class="headerlink" title="基本语法"></a>基本语法</h1><p>Go 语言在很多特性上和C语言非常相近。如果各位看官有C语言基础（或者其他编程语言基础），那么本章的内容阅读起来将会非常轻松，但如果读者没有编程语言基础也没关系，因为本章的内容非常简单易懂。</p>
<h2 id="注释"><a href="#注释" class="headerlink" title="注释"></a>注释</h2><p>注释就是为了<strong style="color:red">增强代码的可读性</strong>，注释起来的代码或者文字不会被程序执行，程序会自动略过注释的部分</p>
<p>写注释是一个非常好的习惯，十分建议多写注释，否则以后你会想打死不写注释的自己╮（￣▽￣）╭</p>
<ol>
<li><p>单行注释</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="comment">// 单行注释，这一行都不会被程序执行 （～￣▽￣～）</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="built_in">println</span>(<span class="string">&quot;Hello World&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>多行注释</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> 不会被执行（～￣▽￣～）</span></span><br><span class="line"><span class="comment"> 多行注释  &lt;（￣︶￣）&gt;</span></span><br><span class="line"><span class="comment"> 不会被执行（～￣▽￣～）</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="built_in">println</span>(<span class="string">&quot;Hello World&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h2 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h2><p>Go语言是静态类型语言，因此变量（variable）是有明确类型的，编译器也会检查变量类型的正确性。</p>
<ul>
<li><p>字面上来理解，变量就是会变化的量。</p>
</li>
<li><p>在数学概念中，变量表示没有固定值且可改变的数。</p>
</li>
<li><p>从计算机系统实现角度来看，变量是一段或多段用来存储数据的内存。</p>
</li>
</ul>
<p>这里的<code>name</code>就是变量，右边的“玄德”就是给这个变量赋值，所以这个变量<code>name</code>的值就是“玄德”</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> name <span class="type">string</span> = <span class="string">&quot;玄德&quot;</span></span><br></pre></td></tr></table></figure>

<p>不用写分号真不错啊&lt;（￣︶￣）&gt;</p>
<h3 id="变量的声明"><a href="#变量的声明" class="headerlink" title="变量的声明"></a>变量的声明</h3><p>在G语言中，声明一个变量一般使用<code>var</code>关键字</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> name <span class="keyword">type</span></span><br></pre></td></tr></table></figure>

<p>这里的<code>type</code>表示变量的类型，就如上面的字符串类型：<code>string</code></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义一个字符型变量 name</span></span><br><span class="line"><span class="keyword">var</span> name <span class="type">string</span></span><br><span class="line"><span class="comment">// 定义一个整形变量 age</span></span><br><span class="line"><span class="keyword">var</span> age <span class="type">int</span></span><br></pre></td></tr></table></figure>

<p>Go语言和许多编程语言不同，它在声明变量时将变量的类型放在变量的名称之后。</p>
<p>这样做的好处就是可以避免像C语言中那样含糊不清的声明形式，例如：<code>int* a, b;</code>， 其中只有 a 是指针而 b 不是，如果你想要这两个变量都是指针，则需要将它们分开书写。</p>
<p>在 Go 语言中，可以轻松地将它们都声明为指针类型：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a, b *<span class="type">int</span></span><br></pre></td></tr></table></figure>

<p>变量的命名遵循驼峰命名法，即首个字母小写，每个新单词的首字母大写，例如：userName、email</p>
<blockquote>
<p>标准格式</p>
</blockquote>
<p>Go语言变量声明的标准格式</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> 变量名 变量类型</span><br></pre></td></tr></table></figure>

<p>变量声明以关键字 var 开头，后置变量类型，行尾无须分号。</p>
<blockquote>
<p>批量格式</p>
</blockquote>
<p>如果觉得单独定义比较麻烦，那么就可以使用批量定义变量，使用关键字 var 和括号，可以将一组变量定义放在一起。</p>
<blockquote>
<p>初始值</p>
</blockquote>
<p>当一个变量被声明后，如果没有给这个变量赋值，那么系统将自动赋予它们默认值：</p>
<ul>
<li>整型和浮点型的默认值是 0 和0.0</li>
<li>字符串变量的默认值是空字符串</li>
<li>布尔型变量默认值是 false</li>
<li>切面、函数、指针变量的默认值是 nil。</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> (</span><br><span class="line">    name <span class="type">string</span></span><br><span class="line">    age <span class="type">int</span></span><br><span class="line">    c [] <span class="type">float32</span></span><br><span class="line">    d <span class="function"><span class="keyword">func</span><span class="params">()</span></span> <span class="type">bool</span></span><br><span class="line">    e <span class="keyword">struct</span> &#123;</span><br><span class="line">        x <span class="type">int</span></span><br><span class="line">    &#125;</span><br><span class="line">)</span><br></pre></td></tr></table></figure>

<blockquote>
<p>Go语言的基本类型</p>
</blockquote>
<ul>
<li>bool</li>
<li>string</li>
<li>int、int8、int16、int32、int64</li>
<li>uint、uint8、uint16、uint32、uint64、uintptr</li>
<li>byte &#x2F;&#x2F; uint8 的别名</li>
<li>rune &#x2F;&#x2F; int32 的别名 代表一个 Unicode 码</li>
<li>float32、float64</li>
<li>complex64、complex128</li>
</ul>
<h3 id="变量的初始化"><a href="#变量的初始化" class="headerlink" title="变量的初始化"></a>变量的初始化</h3><blockquote>
<p>标准格式</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> 变量名 类型 = 表达式</span><br></pre></td></tr></table></figure>

<p>比如，定义一个玄德的信息，可以这么表示</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> name <span class="type">string</span> = <span class="string">&quot;玄德&quot;</span>		<span class="comment">// 定义字符型变量name</span></span><br><span class="line"><span class="keyword">var</span> age <span class="type">int</span> = <span class="number">20</span>			 <span class="comment">// 定义整形变量 age</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">println</span>(name, age)	</span><br></pre></td></tr></table></figure>

<p>在标准格式的基础上，如果将类型省去，编译器会尝试根据等号右边的表达式推导变量的类型。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> name = <span class="string">&quot;玄德&quot;</span></span><br></pre></td></tr></table></figure>

<p>等号右边的部分在编译原理里被称做右值。</p>
<blockquote>
<p>简短变量</p>
</blockquote>
<p>除 var 关键字外，还可使用更加简短的变量定义和初始化语法。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">名字 := 表达式</span><br></pre></td></tr></table></figure>

<p>编译器会根据右值类型推断出左值对应的类型</p>
<p>需要注意的是，简短模式（short variable declaration）有以下限制：</p>
<ul>
<li>定义变量，同时显式初始化。</li>
<li>不能提供数据类型。</li>
<li>只能用在函数内部。</li>
</ul>
<p>因为简洁和灵活的特点，简短变量声明被广泛用于大部分的局部变量声明和初始化，var 形式的声明语句往往是用于需要显式指定变量类型地方，或者因为变量稍后会被重新赋值而初始值无关紧要的地方</p>
<p>注意：由于使用了:&#x3D;，而不是&#x3D;，因此推导声明写法的左值变量必须是没有定义过的变量，若定义过，将会发生编译错误</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">   x:=<span class="number">100</span></span><br><span class="line">   a,s:=<span class="number">1</span>, <span class="string">&quot;abc&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="变量的交换"><a href="#变量的交换" class="headerlink" title="变量的交换"></a>变量的交换</h3><p>编程最简单的算法之一，莫过于变量交换。交换变量的常见算法需要一个中间变量进行变量的临时保存。用传统方法编写变量交换代码如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a <span class="type">int</span> = <span class="number">100</span></span><br><span class="line"><span class="keyword">var</span> b <span class="type">int</span> = <span class="number">200</span></span><br><span class="line"><span class="keyword">var</span> t <span class="type">int</span></span><br><span class="line">t = a</span><br><span class="line">a = b</span><br><span class="line">b = t</span><br><span class="line">Println(a, b)</span><br></pre></td></tr></table></figure>

<p>而在go语言，如今内存已经不再是紧缺资源，所以可以更简单的实现：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a <span class="type">int</span> = <span class="number">100</span></span><br><span class="line"><span class="keyword">var</span> b <span class="type">int</span> = <span class="number">200</span></span><br><span class="line">b, a = a, b</span><br><span class="line">Println(a, b)</span><br></pre></td></tr></table></figure>



<h3 id="匿名变量"><a href="#匿名变量" class="headerlink" title="匿名变量"></a>匿名变量</h3><p>匿名变量的特点是一个下画线 <code>_</code>，<code>_</code> 本身就是一个特殊的标识符，被称为空白标识符。它可以像其他标识符那样用于变量的声明或赋值（任何类型都可以赋值给它），<strong style="color:red">但任何赋给这个标识符的值都将被抛弃</strong>，因此这些值不能在后续的代码中使用，也不可以使用这个标识符作为变量对其它变量进行赋值或运算。使用匿名变量时，只需要在变量声明的地方使用下画线替换即可。例如：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">test</span><span class="params">()</span></span> (<span class="type">int</span>, <span class="type">int</span>) &#123;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">100</span>, <span class="number">200</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	a, _ := test()		</span><br><span class="line">	_, b := test()		</span><br><span class="line">	<span class="built_in">println</span>(a, b)		<span class="comment">//100, 200</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在编码过程中，可能会遇到没有名称的变量、类型或方法。虽然这不是必须的，但有时候这样做可以极大地增强代码的灵活性，这些变量被统称为匿名变量。</p>
<p><strong>匿名变量不占用内存空间，不会分配内存。匿名变量与匿名变量之间也不会因为多次声明而无法使用。</strong></p>
<h3 id="变量的作用域"><a href="#变量的作用域" class="headerlink" title="变量的作用域"></a>变量的作用域</h3><p>一个变量（常量、类型或函数）在程序中都有一定的作用范围，称之为作用域。</p>
<p>了解变量的作用域对我们学习Go语言来说是比较重要的，因为Go语言会在编译时检查每个变量是否使用过，一旦出现未使用的变量，就会报编译错误。如果不能理解变量的作用域，就有可能会带来一些不明所以的编译错误。</p>
<p>根据变量定义位置的不同，可以分为以下三个类型：</p>
<ul>
<li>函数内定义的变量称为局部变量</li>
<li>函数外定义的变量称为全局变量</li>
<li>函数定义中的变量称为形式参数</li>
</ul>
<blockquote>
<p>局部变量</p>
</blockquote>
<p>在函数体内声明的变量称之为局部变量，它们的作用域只在函数体内，函数的参数和返回值变量都属于局部变量。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">//声明局部变量 a 和 b 并赋值</span></span><br><span class="line">	<span class="keyword">var</span> a <span class="type">int</span> = <span class="number">3</span></span><br><span class="line">	<span class="keyword">var</span> b <span class="type">int</span> = <span class="number">4</span></span><br><span class="line">	<span class="comment">//声明局部变量 c 并计算 a 和 b 的和</span></span><br><span class="line">	c := a + b</span><br><span class="line">	fmt.Printf(<span class="string">&quot;a = %d, b = %d, c = %d\n&quot;</span>, a, b, c)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>全局变量</p>
</blockquote>
<p>在函数体外声明的变量称之为全局变量，全局变量只需要在一个源文件中定义，就可以在所有源文件中使用，当然，不包含这个全局变量的源文件需要使用“import”关键字引入全局变量所在的源文件之后才能使用这个全局变量。</p>
<p>全局变量声明必须以 var 关键字开头，如果想要在外部包中使用全局变量的首字母必须大写。</p>
<p>Go语言程序中全局变量与局部变量名称可以相同，但是函数体内的局部变量会被优先考虑。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 声明全局变量</span></span><br><span class="line"><span class="keyword">var</span> a <span class="type">float32</span> = <span class="number">3.14</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">//声明局部变量</span></span><br><span class="line">	<span class="keyword">var</span> a <span class="type">int</span> = <span class="number">3</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;a = %d\n&quot;</span>, a)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="常量"><a href="#常量" class="headerlink" title="常量"></a>常量</h3><p>常量是一个简单的标识符，在程序运行时，不会被修改的量</p>
<p>常量的数据只能是布尔型、数字型（整数型、浮点型和复数）和字符串型。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> name [<span class="keyword">type</span>] = value</span><br></pre></td></tr></table></figure>

<p>在Go语言中，你可以省略类型说明符 [type]，因为编译器可以根据变量的值来推断其类型。</p>
<ul>
<li>显式类型定义： <code>const b string = &quot;abc&quot;</code></li>
<li>隐式类型定义： <code>const b = &quot;abc&quot;</code></li>
</ul>
<p>多个相同类型的声明可以简写为：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> c_name1, c_name2 = value1, value2</span><br></pre></td></tr></table></figure>

<blockquote>
<p>iota 常量计数器</p>
</blockquote>
<p>常量声明可以使用 iota 常量生成器初始化，它用于生成一组以相似规则初始化的常量，但是不用每行都写一遍初始化表达式。</p>
<p>在一个 const 声明语句中，第一个声明的常量所在的行，iota 将会被置为 0，然后在每一个有常量声明的行加一。</p>
<p>在其它编程语言中，这种类型一般被称为枚举类型。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// iota 默认为0</span></span><br><span class="line">	<span class="keyword">const</span> (</span><br><span class="line">		<span class="comment">// 一组常量中，如果某个常量没有初始值，默认和上一行一致</span></span><br><span class="line">		a = <span class="literal">iota</span> <span class="comment">// 0</span></span><br><span class="line">		b        <span class="comment">// 1</span></span><br><span class="line">		c        <span class="comment">// 2</span></span><br><span class="line">	)</span><br><span class="line">	<span class="comment">// 下一个const语句重新计数</span></span><br><span class="line">	<span class="keyword">const</span> (</span><br><span class="line">		<span class="comment">// 常量被赋值不会打断 iota 计数</span></span><br><span class="line">		d = <span class="literal">iota</span>    <span class="comment">// 0</span></span><br><span class="line">		e = <span class="string">&quot;hello&quot;</span> <span class="comment">// hello</span></span><br><span class="line">		f = <span class="literal">iota</span>    <span class="comment">// 2</span></span><br><span class="line">	)</span><br><span class="line">	fmt.Println(a, b, c, d, e, f)</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h2 id="基本数据类型"><a href="#基本数据类型" class="headerlink" title="基本数据类型"></a>基本数据类型</h2><p>Go语言是静态类型语言，在 Go 编程语言中，数据类型用于声明函数和变量，数据类型就是告诉编译器要向系统申请一块多大的内存空间，并知道这块空间表示什么</p>
<h3 id="布尔类型"><a href="#布尔类型" class="headerlink" title="布尔类型"></a>布尔类型</h3><p>一个布尔类型的值只有两种：true 或 false。if 和 for 语句的条件部分都是布尔类型的值，并且<code>==</code>和<code>&lt;</code>等比较操作也会产生布尔型的值。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 默认值为 false</span></span><br><span class="line">	<span class="keyword">var</span> flag <span class="type">bool</span></span><br><span class="line">	<span class="keyword">var</span> flag1 <span class="type">bool</span> = <span class="literal">false</span></span><br><span class="line">	<span class="keyword">var</span> flag2 <span class="type">bool</span> = <span class="literal">true</span></span><br><span class="line"></span><br><span class="line">	<span class="built_in">println</span>(flag)</span><br><span class="line">	<span class="built_in">println</span>(flag1)</span><br><span class="line">	<span class="built_in">println</span>(flag2)</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="数字类型"><a href="#数字类型" class="headerlink" title="数字类型"></a>数字类型</h3><p>整型 int 和浮点型 float32、float64，Go语言支持整型和浮点型数字，并且支持复数，其中位的运算采用补码</p>
<blockquote>
<p>Go也有基于架构的类型，例如：uint 无符号、 int有符号</p>
</blockquote>
<ul>
<li>uint8：  无符号 8 位整形（0 到 255）</li>
<li>uint16：无符号 16 位整形（0 到 65535）</li>
<li>uint32：无符号 32 位整形（0 到 4294967295）</li>
<li>uint64：无符号 64 位整形（0 到 18446744073709551615）</li>
<li>int8：  有符号 8 为整形（-128 到 127）</li>
<li>int16：有符号 16 位整形（-32768 到 32767）</li>
<li>int32：有符号 32 位整形（-2147483648 到 2147483647）</li>
<li>int64：有符号 64 位整形（-9223372036854775808 到 9223372036854775807）</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 定义一个整形</span></span><br><span class="line">	<span class="keyword">var</span> age <span class="type">int</span> = <span class="number">20</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;%d \n&quot;</span>, age)	<span class="comment">// 20</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">// 定义一个浮点型</span></span><br><span class="line">	<span class="comment">// 默认6位小数打印 3.140000</span></span><br><span class="line">	<span class="keyword">var</span> test <span class="type">float64</span> = <span class="number">3.14</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;%f&quot;</span>, test)	<span class="comment">// 3.140000</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>其他数字类型</p>
</blockquote>
<ul>
<li>byte 类似 uint8</li>
<li>rune 类似 int32</li>
<li>uint 32 或 64 位</li>
<li>int 与 uint 一样大小</li>
<li>uintptr 无符号整形，用于存放指针</li>
</ul>
<h3 id="字符类型"><a href="#字符类型" class="headerlink" title="字符类型"></a>字符类型</h3><p>字符有两种形式，分别是字符和字符串（’’ 和 “”）</p>
<p>字符串是一种值类型，且值不可变，即创建某个文本后将无法再次修改这个文本的内容，更深入地讲，字符串是字节的定长数组。</p>
<p>一个字符串是一个<strong>不可改变的字节序列</strong>，字符串可以包含任意的数据，但是通常是用来包含可读的文本，字符串是 UTF-8 字符的一个序列（当字符为 ASCII 码表上的字符时则占用 1 个字节，其它字符根据需要占用 2-4 个字节）。</p>
<p>与C++、Java、Python不同（Java 始终使用 2 个字节），Go语言中字符串也可能根据需要占用 1 至 4 个字节，这样做不仅减少了内存和硬盘空间占用，同时也不用像其它语言那样需要对使用 UTF-8 字符集的文本进行编码和解码。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// \n 为转义字符，表示换行</span></span><br><span class="line">	<span class="keyword">var</span> str <span class="type">string</span></span><br><span class="line">	str = <span class="string">&quot;Hello,World&quot;</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;%T,%s\n&quot;</span>, str, str)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 获取指定的字节</span></span><br><span class="line">    fmt.Printf(<span class="string">&quot;第四个字节是：&quot;</span> + <span class="string">&quot;%c\n&quot;</span>, str[<span class="number">4</span>])</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 单引号和双引号区别，单引号 字符，ASCII字符码</span></span><br><span class="line">	v1 := <span class="string">&#x27;A&#x27;</span></span><br><span class="line">	v2 := <span class="string">&quot;A&quot;</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;%T,%d\n&quot;</span>, v1, v1)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;%T,%s\n&quot;</span>, v2, v2)</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 中国的编码表：GBK</span></span><br><span class="line">	<span class="comment">// Unicode编码表：号称兼容了全世界的文字</span></span><br><span class="line">	v3 := <span class="string">&#x27;中&#x27;</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;%T,%d\n&quot;</span>, v3, v3)</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 字符串拼接</span></span><br><span class="line">	<span class="built_in">println</span>(<span class="string">&quot;hello&quot;</span> + <span class="string">&quot;，xuande&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>常用转义字符：</strong></p>
<ul>
<li>\n：换行符</li>
<li>\r：回车符</li>
<li>\t：tab 键</li>
<li>\u 或 \U：Unicode 字符</li>
<li>\：反斜杠自身</li>
</ul>
<blockquote>
<p>定义多行字符串</p>
</blockquote>
<p>在Go语言中，使用双引号书写字符串的方式是字符串常见表达方式之一，这种双引号字面量不能跨行，如果想要在源码中嵌入一个多行字符串时，就必须使用反引号(键盘上 1 键左边的键，长这样” &#96; “)</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> str = <span class="string">`第一行</span></span><br><span class="line"><span class="string">第二行</span></span><br><span class="line"><span class="string">第三行</span></span><br><span class="line"><span class="string">\r\n</span></span><br><span class="line"><span class="string">`</span></span><br><span class="line">fmt.Println(str)</span><br></pre></td></tr></table></figure>

<blockquote>
<p>UTF-8 和 Unicode 有何区别？</p>
</blockquote>
<p>Unicode 与 ASCII 类似，都是一种字符集。</p>
<p>字符集为每个字符分配一个唯一的 ID，我们使用到的所有字符在 Unicode 字符集中都有一个唯一的 ID，例如上面例子中的 a 在 Unicode 与 ASCII 中的编码都是 97。汉字“你”在 Unicode 中的编码为 20320，在不同国家的字符集中，字符所对应的 ID 也会不同。而无论任何情况下，Unicode 中的字符的 ID 都是不会变化的。</p>
<p>UTF-8 是编码规则，将 Unicode 中字符的 ID 以某种方式进行编码，UTF-8 的是一种变长编码规则，从 1 到 4 个字节不等。编码规则如下：</p>
<ul>
<li>0xxxxxx 表示文字符号 0～127，兼容 ASCII 字符集。</li>
<li>从 128 到 0x10ffff 表示其他字符。</li>
</ul>
<p>根据这个规则，拉丁文语系的字符编码一般情况下每个字符占用一个字节，而中文每个字符占用 3 个字节。</p>
<p>广义的 Unicode 指的是一个标准，它定义了字符集及编码规则，即 Unicode 字符集和 UTF-8、UTF-16 编码等。</p>
<h3 id="指针类型"><a href="#指针类型" class="headerlink" title="指针类型"></a>指针类型</h3><h3 id="数据类型转换"><a href="#数据类型转换" class="headerlink" title="数据类型转换"></a>数据类型转换</h3><p>在必要以及可行的情况下，一个类型的值可以被转换成另一种类型的值。<strong>由于Go语言不存在隐式类型转换，因此所有的类型转换都必须显式的声明：</strong></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">valueOfTypeB = typeB(valueOfTypeA)</span><br></pre></td></tr></table></figure>

<p>类型 B 的值 &#x3D; 类型 B(类型 A 的值)</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	a := <span class="number">5.0</span>    <span class="comment">// float</span></span><br><span class="line">	b := <span class="type">int</span>(a) <span class="comment">// 强转为int</span></span><br><span class="line"></span><br><span class="line">	fmt.Printf(<span class="string">&quot;%T,%f\n&quot;</span>, a, a)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;%T,%d\n&quot;</span>, b, b)</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>型转换只能在定义正确的情况下转换成功，例如从一个取值范围较小的类型转换到一个取值范围较大的类型（将 int16 转换为  int32）。当从一个取值范围较大的类型转换到取值范围较小的类型时（将 int32 转换为 int16 或将 float32 转换为  int），会发生精度丢失（截断）的情况。</p>
<h2 id="运算符"><a href="#运算符" class="headerlink" title="运算符"></a>运算符</h2><ul>
<li>算术运算符</li>
<li>关系运算符</li>
<li>逻辑运算符</li>
<li>位运算符</li>
<li>赋值运算符</li>
<li>其他运算符</li>
</ul>
<blockquote>
<p>Go语言运算符优先级</p>
</blockquote>
<p>先计算乘法后计算加法，说明乘法运算符的优先级比加法运算符的优先级高。所谓优先级，就是当多个运算符出现在同一个表达式中时，先执行哪个运算符。</p>
<table>
<thead>
<tr>
<th>优先级</th>
<th>分类</th>
<th>运算符</th>
<th>结合性</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>逗号运算符</td>
<td>,</td>
<td>从左到右</td>
</tr>
<tr>
<td>2</td>
<td>赋值运算符</td>
<td>&#x3D;、+&#x3D;、-&#x3D;、*&#x3D;、&#x2F;&#x3D;、 %&#x3D;、 &gt;&#x3D;、 &lt;&lt;&#x3D;、&amp;&#x3D;、^&#x3D;、|&#x3D;</td>
<td>从右到左</td>
</tr>
<tr>
<td>3</td>
<td>逻辑或</td>
<td>||</td>
<td>从左到右</td>
</tr>
<tr>
<td>4</td>
<td>逻辑与</td>
<td>&amp;&amp;</td>
<td>从左到右</td>
</tr>
<tr>
<td>5</td>
<td>按位或</td>
<td>|</td>
<td>从左到右</td>
</tr>
<tr>
<td>6</td>
<td>按位异或</td>
<td>^</td>
<td>从左到右</td>
</tr>
<tr>
<td>7</td>
<td>按位与</td>
<td>&amp;</td>
<td>从左到右</td>
</tr>
<tr>
<td>8</td>
<td>相等&#x2F;不等</td>
<td>&#x3D;&#x3D;、!&#x3D;</td>
<td>从左到右</td>
</tr>
<tr>
<td>9</td>
<td>关系运算符</td>
<td>&lt;、&lt;&#x3D;、&gt;、&gt;&#x3D;</td>
<td>从左到右</td>
</tr>
<tr>
<td>10</td>
<td>位移运算符</td>
<td>&lt;&lt;、&gt;&gt;</td>
<td>从左到右</td>
</tr>
<tr>
<td>11</td>
<td>加法&#x2F;减法</td>
<td>+、-</td>
<td>从左到右</td>
</tr>
<tr>
<td>12</td>
<td>乘法&#x2F;除法&#x2F;取余</td>
<td>*（乘号）、&#x2F;、%</td>
<td>从左到右</td>
</tr>
<tr>
<td>13</td>
<td>单目运算符</td>
<td>!、*（指针）、&amp; 、++、–、+（正号）、-（负号）</td>
<td>从右到左</td>
</tr>
<tr>
<td>14</td>
<td>后缀运算符</td>
<td>( )、[ ]、-&gt;</td>
<td>从左到右</td>
</tr>
</tbody></table>
<p>注意：优先级值越大，表示优先级越高</p>
<h3 id="算术运算符"><a href="#算术运算符" class="headerlink" title="算术运算符"></a>算术运算符</h3><p>简单的加减乘除，取余就是相除之后的余数，++ 代表自增、– 代表自减</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> a <span class="type">int</span> = <span class="number">10</span></span><br><span class="line">	<span class="keyword">var</span> b <span class="type">int</span> = <span class="number">3</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">// + - * / % ++ --</span></span><br><span class="line">	<span class="built_in">println</span>(a + b) <span class="comment">// 13</span></span><br><span class="line">	<span class="built_in">println</span>(a - b) <span class="comment">// 7</span></span><br><span class="line">	<span class="built_in">println</span>(a * b) <span class="comment">// 30</span></span><br><span class="line">	<span class="built_in">println</span>(a / b) <span class="comment">// 3</span></span><br><span class="line">	<span class="built_in">println</span>(a % b) <span class="comment">// 1</span></span><br><span class="line">	a++            <span class="comment">// a = a + 1</span></span><br><span class="line">	<span class="built_in">println</span>(a)     <span class="comment">// 11</span></span><br><span class="line">	b--            <span class="comment">// a = a - 1</span></span><br><span class="line">	<span class="built_in">println</span>(b)     <span class="comment">// 12</span></span><br><span class="line">	<span class="built_in">println</span>(a, b)  <span class="comment">// 11 2</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="关系运算符"><a href="#关系运算符" class="headerlink" title="关系运算符"></a>关系运算符</h3><p>关系运算符的结果都是布尔值，它尝尝会出现在判断语句当中</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> a <span class="type">int</span> = <span class="number">11</span></span><br><span class="line">	<span class="keyword">var</span> b <span class="type">int</span> = <span class="number">10</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">// == 等于 = 赋值</span></span><br><span class="line">	<span class="comment">// 关系运算符，结果都是bool（布尔值）</span></span><br><span class="line">	<span class="built_in">println</span>(a == b) <span class="comment">// 等于</span></span><br><span class="line">	<span class="built_in">println</span>(a != b) <span class="comment">// 不等于</span></span><br><span class="line">	<span class="built_in">println</span>(a &gt; b)</span><br><span class="line">	<span class="built_in">println</span>(a &lt; b)</span><br><span class="line">	<span class="built_in">println</span>(a &gt;= b)</span><br><span class="line">	<span class="built_in">println</span>(a &lt;= b)</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="逻辑运算符"><a href="#逻辑运算符" class="headerlink" title="逻辑运算符"></a>逻辑运算符</h3><p>逻辑运算符等同于高中数学里面的与、或、非</p>
<ul>
<li>逻辑与（&amp;&amp;）：两边都是真（True），则条件为真（True），否则为假（False）</li>
<li>逻辑或（||）：两边有一个为 True，怎该条件为 True，否则为 False</li>
<li>逻辑非（ ! ）：如果为 True，则变为 False，反之亦然</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> a <span class="type">bool</span> = <span class="literal">true</span></span><br><span class="line">	<span class="keyword">var</span> b <span class="type">bool</span> = <span class="literal">false</span></span><br><span class="line">	<span class="keyword">var</span> c <span class="type">bool</span></span><br><span class="line">	<span class="comment">// 逻辑与（&amp;&amp;）：两边都为真，结果为真，反之为假</span></span><br><span class="line">	c = a &amp;&amp; b</span><br><span class="line">	<span class="built_in">println</span>(c) <span class="comment">// false</span></span><br><span class="line">	<span class="comment">// 逻辑或（||）：两边都为假，结果为假，反之为真</span></span><br><span class="line">	c = a || b</span><br><span class="line">	<span class="built_in">println</span>(c) <span class="comment">// true</span></span><br><span class="line">	<span class="comment">// 逻辑非（！）：改变布尔值，真变假、假变真</span></span><br><span class="line">	c = a</span><br><span class="line">	<span class="built_in">println</span>(c) <span class="comment">// true</span></span><br><span class="line">	c = !a</span><br><span class="line">	<span class="built_in">println</span>(c) <span class="comment">// false</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="位运算符"><a href="#位运算符" class="headerlink" title="位运算符"></a>位运算符</h3><p>乍一看与逻辑运算符很相似，但它俩可是天差地别，位运算符是对二进制进行操作</p>
<p><strong>二进制</strong>：通常用两个不同的符号0（代表零）和1（代表一）来表示，我们平常使用的是十进制，逢十进一；二进制是逢二进一</p>
<table>
<thead>
<tr>
<th>十进制</th>
<th>二进制</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>2</td>
<td>10</td>
</tr>
<tr>
<td>3</td>
<td>11</td>
</tr>
<tr>
<td>……</td>
<td>…..</td>
</tr>
<tr>
<td>10</td>
<td>1010</td>
</tr>
<tr>
<td>11</td>
<td>1011</td>
</tr>
</tbody></table>
<p><strong>所有的位运算都是建立在二进制上的</strong></p>
<ul>
<li>按位与（ &amp; ）：都为1结果为1，否则为0</li>
<li>按位或（ | ）：都为0结果为0，否则为1</li>
<li>按位异或（ ^ ）：不同为1，相同为0</li>
<li>左移运算符（ &lt;&lt; ）：二进制位全部左移若干位</li>
<li>右移运算符（ &gt;&gt; ）：二进制位全部右移若干位</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">	  位运算案例</span></span><br><span class="line"><span class="comment">	60	0011 1100	|	60 0011 1100</span></span><br><span class="line"><span class="comment">	13	0000 1101	|	------------</span></span><br><span class="line"><span class="comment">	-------------	|	&lt;&lt; 0111 1000</span></span><br><span class="line"><span class="comment">	&amp;	0000 1100	|	&gt;&gt; 0001 1110</span></span><br><span class="line"><span class="comment">	|	0011 1101	|</span></span><br><span class="line"><span class="comment">	^	0011 0001	|</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">	*/</span></span><br><span class="line">	<span class="keyword">var</span> a <span class="type">uint</span> = <span class="number">60</span></span><br><span class="line">	<span class="keyword">var</span> b <span class="type">uint</span> = <span class="number">13</span></span><br><span class="line">	<span class="keyword">var</span> c <span class="type">uint</span> = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">	c = a &amp; b</span><br><span class="line">	fmt.Printf(<span class="string">&quot;十进制：%d, 二进制：%b\n&quot;</span>, c, c) <span class="comment">// 十进制：12, 二进制：1100</span></span><br><span class="line">	c = a | b</span><br><span class="line">	fmt.Printf(<span class="string">&quot;十进制：%d, 二进制：%b\n&quot;</span>, c, c) <span class="comment">// 十进制：61, 二进制：111101</span></span><br><span class="line">	c = a ^ b</span><br><span class="line">	fmt.Printf(<span class="string">&quot;十进制：%d, 二进制：%b\n&quot;</span>, c, c) <span class="comment">// 十进制：49, 二进制：110001</span></span><br><span class="line"></span><br><span class="line">	c = a &lt;&lt; <span class="number">2</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;十进制：%d, 二进制：%b\n&quot;</span>, c, c) <span class="comment">// 十进制：240, 二进制：11110000</span></span><br><span class="line">	c = a &gt;&gt; <span class="number">2</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;十进制：%d, 二进制：%b\n&quot;</span>, c, c) <span class="comment">// 十进制：15, 二进制：1111</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="赋值运算符"><a href="#赋值运算符" class="headerlink" title="赋值运算符"></a>赋值运算符</h3><p>简化操作，这里演示一下+&#x3D;和-&#x3D;，其他同理</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> a <span class="type">int</span> = <span class="number">66</span></span><br><span class="line">	<span class="keyword">var</span> b <span class="type">int</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">// = 赋值</span></span><br><span class="line">	b = a</span><br><span class="line">	<span class="built_in">println</span>(b) <span class="comment">// 66</span></span><br><span class="line">	<span class="comment">// += 等效于 b = a + b</span></span><br><span class="line">	b += a</span><br><span class="line">	<span class="built_in">println</span>(b) <span class="comment">// 132</span></span><br><span class="line">	<span class="comment">// -= 等效于 b = a - b</span></span><br><span class="line">	b -= a</span><br><span class="line">	<span class="built_in">println</span>(b) <span class="comment">// 66</span></span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="其他运算符"><a href="#其他运算符" class="headerlink" title="其他运算符"></a>其他运算符</h3><ul>
<li>&amp;：返回变量存储的地址</li>
<li>*：指针变量</li>
</ul>
<h2 id="指针"><a href="#指针" class="headerlink" title="指针"></a>指针</h2><hr>
<h1 id="流程控制"><a href="#流程控制" class="headerlink" title="流程控制"></a>流程控制</h1><p>程控制是每种编程语言控制逻辑走向和执行次序的重要部分，流程控制可以说是一门语言的“经脉”</p>
<p>Go 语言的常用流程控制有 if 和 for，而 switch 和 goto 主要是为了简化代码、降低重复代码而生的结构，属于扩展类的流程控制。</p>
<p>程序的流程结构分为三种：顺序结构、选择结构、循环结构</p>
<p>顺序结构：从上到下，逐行执行</p>
<p>选择结构：条件满足才会继续执行</p>
<ul>
<li>if</li>
<li>switch</li>
<li>select</li>
</ul>
<p>循环结构：条件满足会被反复执行0~n次</p>
<ul>
<li>for</li>
</ul>
<h2 id="选择结构"><a href="#选择结构" class="headerlink" title="选择结构"></a>选择结构</h2><ul>
<li>if</li>
<li>switch</li>
<li>select</li>
</ul>
<h3 id="if语句"><a href="#if语句" class="headerlink" title="if语句"></a>if语句</h3><p>在Go语言中，关键字 if 是用于测试某个条件（布尔型或逻辑型）的语句，如果该条件成立，则会执行 if 后由大括号<code>&#123;&#125;</code>括起来的代码块，否则就忽略该代码块继续执行后续的代码。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> score <span class="type">int</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;请输入成绩：&quot;</span>)</span><br><span class="line">	fmt.Scanln(&amp;score) <span class="comment">// 对score的地址进行赋值</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;你输入的成绩为：%d\n&quot;</span>, score)</span><br><span class="line">	<span class="keyword">if</span> score &gt;= <span class="number">90</span> &amp;&amp; score &lt;= <span class="number">100</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;评级为：A&quot;</span>)</span><br><span class="line">	&#125; <span class="keyword">else</span> <span class="keyword">if</span> score &gt;= <span class="number">80</span> &amp;&amp; score &lt; <span class="number">90</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;评级为：B&quot;</span>)</span><br><span class="line">	&#125; <span class="keyword">else</span> <span class="keyword">if</span> score &gt;= <span class="number">70</span> &amp;&amp; score &lt; <span class="number">80</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;评级为：C&quot;</span>)</span><br><span class="line">	&#125; <span class="keyword">else</span> <span class="keyword">if</span> score &gt;= <span class="number">60</span> &amp;&amp; score &lt; <span class="number">70</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;评级为：D&quot;</span>)</span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;评级为：不及格&quot;</span>)</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>if嵌套语句</p>
</blockquote>
<p>有时一个判断条件是无法满足需求的，这时就需要if语句嵌套了</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> 布尔表达式<span class="number">1</span> &#123;</span><br><span class="line">	<span class="comment">// 布尔表达式1为true时执行</span></span><br><span class="line">	<span class="keyword">if</span> 布尔表达式<span class="number">2</span> &#123;</span><br><span class="line">		<span class="comment">//布尔表达式2为true时执行</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="switch语句"><a href="#switch语句" class="headerlink" title="switch语句"></a>switch语句</h3><p>Go语言 switch 语句的表达式不需要为常量，甚至不需要为整数，case  按照从上到下的顺序进行求值，直到找到匹配的项，<strong>如果 switch 没有表达式，则对 true 进行匹配</strong>，因此，可以将 if else-if  else 改写成一个 switch。</p>
<p>Go语言改进了 switch 的语法设计，每一个case分支都是<strong>唯一的</strong>，从上到下依次测试，因此不需要通过 break 语句跳出当前 case 代码块以避免执行到下一行。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> a = <span class="string">&quot;hello&quot;</span></span><br><span class="line">	<span class="keyword">switch</span> a &#123;</span><br><span class="line">	<span class="keyword">case</span> <span class="string">&quot;hello&quot;</span>:</span><br><span class="line">		fmt.Println(<span class="number">1</span>)		<span class="comment">// 匹配成功，输出1，终止switch</span></span><br><span class="line">	<span class="keyword">case</span> <span class="string">&quot;world&quot;</span>:</span><br><span class="line">		fmt.Println(<span class="number">2</span>)		<span class="comment">// 不会执行</span></span><br><span class="line">	<span class="keyword">default</span>:</span><br><span class="line">		fmt.Println(<span class="number">0</span>)		<span class="comment">// case分支全部匹配失败时，执行该语句</span></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Go语言的 switch 语句可以一分支多值，也可以case后面添加表达式</p>
<ul>
<li><p>一分支多值</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="string">&quot;mum&quot;</span></span><br><span class="line"><span class="keyword">switch</span> a &#123;</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;mum&quot;</span>, <span class="string">&quot;daddy&quot;</span>:	<span class="comment">// 注意逗号</span></span><br><span class="line">    fmt.Println(<span class="string">&quot;family&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>分支表达式</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> r <span class="type">int</span> = <span class="number">11</span></span><br><span class="line"><span class="keyword">switch</span> &#123;				<span class="comment">// 默认匹配itrue</span></span><br><span class="line"><span class="keyword">case</span> r &gt; <span class="number">10</span> &amp;&amp; r &lt; <span class="number">20</span>:</span><br><span class="line">    fmt.Println(r)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
<blockquote>
<p>fallthrough——兼容C语言的 case 设计</p>
</blockquote>
<p>在Go语言中 case 是一个独立的代码块，执行完毕后不会像C语言那样紧接着执行下一个 case，但是为了兼容一些移植代码，依然加入了 <strong>fallthrough</strong> 关键字来实现这一功能。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> s = <span class="string">&quot;hello&quot;</span></span><br><span class="line"><span class="keyword">switch</span> &#123;</span><br><span class="line"><span class="keyword">case</span> s == <span class="string">&quot;hello&quot;</span>:</span><br><span class="line">    fmt.Println(<span class="string">&quot;hello&quot;</span>)</span><br><span class="line">    <span class="keyword">fallthrough</span>				<span class="comment">// case穿透，不管下个条件是否满足，都会执行</span></span><br><span class="line"><span class="keyword">case</span> s != <span class="string">&quot;world&quot;</span>:</span><br><span class="line">    fmt.Println(<span class="string">&quot;world&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="循环结构"><a href="#循环结构" class="headerlink" title="循环结构"></a>循环结构</h2><p>与多数语言不同的是，Go语言中的循环语句只支持 for 关键字，而不支持 while 和 do-while 结构，关键字 for 的基本使用方法与C语言和C++中非常接近</p>
<ul>
<li>for</li>
<li>break</li>
</ul>
<h3 id="for语句"><a href="#for语句" class="headerlink" title="for语句"></a>for语句</h3><p>for循环是一个循环控制结构，可以执行指定次数的循环。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	sum := <span class="number">0</span></span><br><span class="line">    <span class="comment">// for 条件起始值; 循环条件; 操作控制变量</span></span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt;= <span class="number">6</span>; i++ &#123;</span><br><span class="line">		sum += i</span><br><span class="line">	&#125;</span><br><span class="line">	fmt.Println(sum)			<span class="comment">// 21</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可以看到比较大的一个不同在于 for 后面的条件表达式不需要用圆括号<code>()</code>括起来，Go语言还进一步考虑到无限循环的场景，让开发者不用写无聊的 <code>for(;;)&#123;&#125;</code>和<code>do&#123;&#125; while(1);</code></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	sum := <span class="number">0</span></span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		sum++</span><br><span class="line">		fmt.Println(sum) 		<span class="comment">// 无限循环（记得停止，否则会卡死）</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>continue 结束本次循环，开启下一次循环</p>
</blockquote>
<p>Go语言中 continue 语句可以结束当前循环，开始下一次的循环迭代过程，仅限在 for 循环内使用，在 continue 语句后添加标签时，表示开始标签对应的循环</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">1</span>; i &lt;= <span class="number">6</span>; i++ &#123;</span><br><span class="line">		<span class="keyword">if</span> i == <span class="number">5</span> &#123;</span><br><span class="line">			<span class="keyword">continue</span></span><br><span class="line">		&#125;</span><br><span class="line">		fmt.Println(i)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	fmt.Println(<span class="string">&quot;==============我是分界线（～￣▽￣～）=================&quot;</span>)</span><br><span class="line"></span><br><span class="line">OuterLoop:</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">2</span>; i++ &#123;</span><br><span class="line">		<span class="keyword">for</span> j := <span class="number">0</span>; j &lt; <span class="number">5</span>; j++ &#123;</span><br><span class="line">			<span class="keyword">switch</span> j &#123;</span><br><span class="line">			<span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">				fmt.Println(i, j)</span><br><span class="line">				<span class="keyword">continue</span> OuterLoop <span class="comment">// 跳转到标签</span></span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="break"><a href="#break" class="headerlink" title="break"></a>break</h3><p>Go语言中 break 语句可以结束 for、switch 和 select 的代码块，另外 break 语句还可以在语句后面添加标签，表示退出某个标签对应的代码块，标签要求必须定义在对应的 for、switch 和 select 的代码块上。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	sum := <span class="number">0</span></span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		sum++</span><br><span class="line">		<span class="keyword">if</span> sum &gt; <span class="number">100</span> &#123;</span><br><span class="line">			<span class="keyword">break</span> <span class="comment">// 跳出循环</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	fmt.Println(sum)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="键值循环"><a href="#键值循环" class="headerlink" title="键值循环"></a>键值循环</h3><p>for range 结构是Go语言特有的一种的迭代结构，在许多情况下都非常有用，for range 可以遍历数组、切片、字符串、map 及通道（channel），for range 语法上类似于其它语言中的 foreach 语句。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> str <span class="type">string</span> = <span class="string">&quot;hello,xuande&quot;</span></span><br><span class="line">    <span class="comment">// 返回下标和对应的值</span></span><br><span class="line">	<span class="keyword">for</span> key, val := <span class="keyword">range</span> str &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;key:%d val:%c\n&quot;</span>, key, val)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><ul>
<li><p>九九乘法表</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 遍历, 决定处理第几行</span></span><br><span class="line">	<span class="keyword">for</span> y := <span class="number">1</span>; y &lt;= <span class="number">9</span>; y++ &#123;</span><br><span class="line">		<span class="comment">// 遍历, 决定这一行有多少列</span></span><br><span class="line">		<span class="keyword">for</span> x := <span class="number">1</span>; x &lt;= y; x++ &#123;</span><br><span class="line">			fmt.Printf(<span class="string">&quot;%d*%d=%d &quot;</span>, x, y, x*y)</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">// 手动生成回车</span></span><br><span class="line">		fmt.Println()</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>打印6x6方阵</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> j := <span class="number">0</span>; j &lt; <span class="number">5</span>; j++ &#123;</span><br><span class="line">		<span class="keyword">for</span> i := <span class="number">0</span>; i &lt;= <span class="number">5</span>; i++ &#123;</span><br><span class="line">			fmt.Print(<span class="string">&quot;* &quot;</span>)</span><br><span class="line">		&#125;</span><br><span class="line">		fmt.Println()</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>打印松树</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 上半部分</span></span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">5</span>; i++ &#123;</span><br><span class="line">		<span class="keyword">for</span> j := <span class="number">5</span>; j &gt;= i; j-- &#123;</span><br><span class="line">			<span class="built_in">print</span>(<span class="string">&quot; &quot;</span>)</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">for</span> k := <span class="number">0</span>; k &lt; <span class="number">2</span>*i+<span class="number">1</span>; k++ &#123;</span><br><span class="line">			<span class="built_in">print</span>(<span class="string">&quot;*&quot;</span>)</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="built_in">println</span>()</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 下半部分</span></span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">2</span>; i++ &#123;</span><br><span class="line">		<span class="keyword">for</span> j := <span class="number">0</span>; j &lt; <span class="number">5</span>; j++ &#123;</span><br><span class="line">			<span class="built_in">print</span>(<span class="string">&quot; &quot;</span>)</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">for</span> k := <span class="number">0</span>; k &lt; <span class="number">3</span>; k++ &#123;</span><br><span class="line">			<span class="built_in">print</span>(<span class="string">&quot;*&quot;</span>)</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="built_in">println</span>()</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
<li><p>冒泡排序</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 定义切片，进行引用传递</span></span><br><span class="line">	arr := []<span class="type">int</span>&#123;<span class="number">5</span>, <span class="number">1</span>, <span class="number">4</span>, <span class="number">2</span>, <span class="number">8</span>&#125;</span><br><span class="line">	<span class="comment">// 使用协程加快速度</span></span><br><span class="line">	<span class="keyword">go</span> bubbleSort(arr)</span><br><span class="line">	fmt.Println(arr)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">bubbleSort</span><span class="params">(arr []<span class="type">int</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> flag = <span class="literal">true</span></span><br><span class="line">	<span class="keyword">var</span> n = <span class="built_in">len</span>(arr)</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; n<span class="number">-1</span>; i++ &#123;</span><br><span class="line">		<span class="keyword">for</span> j := <span class="number">0</span>; j &lt; n-i<span class="number">-1</span>; j++ &#123;</span><br><span class="line">			<span class="keyword">if</span> arr[j] &gt; arr[j+<span class="number">1</span>] &#123;</span><br><span class="line">				temp := arr[j]</span><br><span class="line">				arr[j] = arr[j+<span class="number">1</span>]</span><br><span class="line">				arr[j+<span class="number">1</span>] = temp</span><br><span class="line">				flag = <span class="literal">false</span></span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span> flag &#123;</span><br><span class="line">			<span class="keyword">continue</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ul>
<hr>
<h1 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h1><p>函数是组织好的、可重复使用的、用来实现单一或相关联功能的代码段，其可以提高应用的模块性和代码的重复利用率。</p>
<p>Go 语言支持普通函数、匿名函数和闭包，从设计上对函数进行了优化和改进，让函数使用起来更加方便。</p>
<p><strong>Go 语言函数：</strong></p>
<ul>
<li>函数是基本的代码块，用于执行一个任务</li>
<li>Go语言最少有个main()函数</li>
<li>函数本身可以作为值进行传递</li>
<li>支持匿名函数和闭包（closure）</li>
<li>函数可以满足接口</li>
<li>可以通过函数来划分不同的功能，逻辑上每个函数执行的是指定的任务</li>
<li>函数声明告诉了编译器函数的名称、返回类型和参数</li>
</ul>
<h2 id="函数的声明"><a href="#函数的声明" class="headerlink" title="函数的声明"></a>函数的声明</h2><p>函数构成了代码执行的逻辑结构，在Go语言中，函数的基本组成为：关键字 func、函数名、参数列表、返回值、函数体和返回语句，每一个程序都包含很多的函数，函数是基本的代码块。</p>
<p>Go语言里面拥三种类型的函数：</p>
<ul>
<li>普通的带有名字的函数</li>
<li>匿名函数或者 lambda 函数</li>
<li>方法</li>
</ul>
<p>Go语言函数定义格式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> 函数名<span class="params">(形参列表)</span></span>(返回值列表)&#123;</span><br><span class="line">    函数体</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>形式参数列表描述了函数的参数名以及参数类型，这些参数作为局部变量，其值由参数调用者提供，形式参数简单来说就是用来<strong>接收外部数据</strong>的参数。</p>
<p>返回值列表描述了函数返回值的变量名以及类型，如果函数返回一个无名变量或者没有返回值，返回值列表的括号是可以省略的。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="comment">// 实际参数：4,2</span></span><br><span class="line">    <span class="comment">// 形参和实参必须对应</span></span><br><span class="line">    result := add(<span class="number">4</span>, <span class="number">2</span>)</span><br><span class="line">	<span class="built_in">print</span>(result)		<span class="comment">// 打印结果：6</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义一个相加函数add(函数名)</span></span><br><span class="line"><span class="comment">// 形式参数：a，b；返回值列表：int；</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">add</span><span class="params">(a, b <span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">	c := a + b</span><br><span class="line">    <span class="comment">// 如果函数有返回值，那么就必须使用return语句</span></span><br><span class="line">	<span class="keyword">return</span> c</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>函数访问规则</p>
</blockquote>
<p><strong>函数名首字母小写，只能在本包访问，函数名首字母大写，可以在本包和其他包访问</strong></p>
<h2 id="内置函数"><a href="#内置函数" class="headerlink" title="内置函数"></a>内置函数</h2><p>Golang设计者为了编程方便，提供了一些函数，这些函数由于不用导包就可以直接使用，所以这些函数被称为内置函数&#x2F;内建函数</p>
<p>内置函数位置：builtin包下</p>
<blockquote>
<p>常用函数</p>
</blockquote>
<ul>
<li>len函数：统计字符串的长度，按字节进行统计</li>
<li>new函数：分配内存，主要用来分配值类型（int、float、string、array、struct）</li>
<li>make函数：分配内存，主要用来分配引用类型（指针、切片、管道、接口等）</li>
</ul>
<h2 id="可变参数"><a href="#可变参数" class="headerlink" title="可变参数"></a>可变参数</h2><p>可变参数是指函数传入的参数个数是可变的（类型确定，个数不确定）</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;传入2个参数:&quot;</span>)</span><br><span class="line">	getSum(<span class="number">1</span>, <span class="number">2</span>)</span><br><span class="line">	fmt.Println(<span class="string">&quot;传入3个参数:&quot;</span>)</span><br><span class="line">	getSum(<span class="number">1</span>, <span class="number">2</span>, <span class="number">66</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ... 可变参数</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">getSum</span><span class="params">(args ...<span class="type">int</span>)</span></span> &#123;</span><br><span class="line">	sum := <span class="number">0</span></span><br><span class="line">	<span class="keyword">for</span> _, arg := <span class="keyword">range</span> args &#123;</span><br><span class="line">		sum += arg</span><br><span class="line">		fmt.Println(arg)</span><br><span class="line">	&#125;</span><br><span class="line">	fmt.Println(<span class="string">&quot;sum:&quot;</span>, sum)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>注意：</p>
<ul>
<li>可变参数只能放在参数列表的最后</li>
<li>一个函数最多只有一个可变参数</li>
</ul>
<blockquote>
<p>任意类型的可变参数</p>
</blockquote>
<p>之前的例子中将可变参数类型约束为 int，如果你希望传任意类型，可以指定类型为 <code>interface&#123;&#125;</code>，下面是Go语言标准库中 fmt.Printf() 的函数原型：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Printf</span><span class="params">(format <span class="type">string</span>, args ...<span class="keyword">interface</span>&#123;&#125;)</span></span> &#123;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>用 interface{} 传递任意类型数据是Go语言的惯例用法，使用 interface{} 仍然是类型安全的，这和 C&#x2F;C++ 不太一样</p>
<h2 id="参数传递"><a href="#参数传递" class="headerlink" title="参数传递"></a>参数传递</h2><p>数据的存储特点分为：</p>
<ul>
<li>值传递：操作的是数据的本身，int、string、bool、float64、array。。。</li>
<li>引用传递：操作的是数据的地址，slice、map、chan。。。</li>
</ul>
<blockquote>
<p>值传递</p>
</blockquote>
<p>使用普通变量作为函数参数的时候，在传递参数时只是对变量值得拷贝，即将实参的值复制给变参，当函数对变参进行处理时，并不会影响原来实参的值。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="comment">// 定义数组</span></span><br><span class="line">	arr1 := [<span class="number">4</span>]<span class="type">int</span>&#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>&#125;</span><br><span class="line">	fmt.Println(<span class="string">&quot;默认数据arr1&quot;</span>, arr1) 				<span class="comment">// 默认数据arr1 [1 2 3 4]</span></span><br><span class="line">	update(arr1)</span><br><span class="line">	fmt.Println(<span class="string">&quot;调用函数后数据arr1&quot;</span>, arr1) 		 <span class="comment">// 调用函数后数据arr1 [1 2 3 4]</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">update</span><span class="params">(arr2 [4]<span class="type">int</span>)</span></span> &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;接受数据arr2：&quot;</span>, arr2) 		 <span class="comment">// 接受数据arr2： [1 2 3 4]</span></span><br><span class="line">	arr2[<span class="number">0</span>] = <span class="number">66</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;修改后数据arr2：&quot;</span>, arr2) 	<span class="comment">// 修改后数据arr2： [66 2 3 4]</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>解析：</p>
<ul>
<li>arr2的数据是从arr1复制的，所以它俩处在不同的内存空间</li>
<li>由于是拷贝的副本，所以修改arr2并不会影响arr1</li>
<li>值类型的数据，默认都是值传递：基础类型、array、struct</li>
</ul>
<blockquote>
<p>引用传递</p>
</blockquote>
<p>函数的变量不仅可以使用普通变量，还可以使用指针变量，使用指针变量作为函数的参数时，在进行参数传递时将是一个地址，即将实参的内存地址复制给变参，这时对变参的修改也将会影响到实参的值。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="comment">// 定义切片</span></span><br><span class="line">	s1 := []<span class="type">int</span>&#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>&#125;</span><br><span class="line">	fmt.Println(<span class="string">&quot;默认数据s1&quot;</span>, s1) <span class="comment">// 默认数据s1 [1 2 3 4]</span></span><br><span class="line">	update(s1)</span><br><span class="line">	fmt.Println(<span class="string">&quot;调用函数后数据s1&quot;</span>, s1) <span class="comment">// 调用函数后数据s1 [66 2 3 4]</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">update</span><span class="params">(s2 []<span class="type">int</span>)</span></span> &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;接受数据s2：&quot;</span>, s2) <span class="comment">// 接受数据s2： [1 2 3 4]</span></span><br><span class="line">	s2[<span class="number">0</span>] = <span class="number">66</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;修改后数据s2：&quot;</span>, s2) <span class="comment">// 修改后数据s2： [66 2 3 4]</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>解析：</p>
<ul>
<li>引用传递传递的是内存地址</li>
<li>由于传递的是地址，所以是同一片内存空间</li>
<li>修改变参s2会影响到实参s1</li>
</ul>
<h2 id="递归函数"><a href="#递归函数" class="headerlink" title="递归函数"></a>递归函数</h2><p>很对编程语言都支持递归函数，Go语言也不例外，所谓递归函数指的是在<strong>函数内部调用函数自身</strong>的函数，从数学解题思路来说，递归就是把一个大问题拆分成多个小问题，再各个击破，在实际开发过程中，递归函数可以解决许多数学问题，如计算给定数字阶乘、产生斐波系列等。</p>
<p>构成递归需要具备以下条件：</p>
<ul>
<li>一个问题可以被拆分成多个子问题；</li>
<li>拆分前的原问题与拆分后的子问题除了数据规模不同，但处理问题的思路是一样的；</li>
<li>不能无限制的调用本身，子问题需要有退出递归状态的条件。</li>
</ul>
<p><strong>注意：编写递归函数时，一定要有终止条件，否则就会无限调用下去，直到内存溢出。</strong></p>
<blockquote>
<p>斐波那锲数列</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    result := <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i := <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++ &#123;</span><br><span class="line">        result = fibonacci(i)</span><br><span class="line">        fmt.Printf(<span class="string">&quot;fibonacci(%d) is: %d\n&quot;</span>, i, result)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">fibonacci</span><span class="params">(n <span class="type">int</span>)</span></span> (res <span class="type">int</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> n &lt;= <span class="number">2</span> &#123;</span><br><span class="line">        res = <span class="number">1</span></span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        res = fibonacci(n<span class="number">-1</span>) + fibonacci(n<span class="number">-2</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="函数变量"><a href="#函数变量" class="headerlink" title="函数变量"></a>函数变量</h2><p>在Go语言中，函数也是一种类型，可以和其他类型一样保存在变量中，下面的代码定义了一个函数变量 f，并将一个函数名为 fire() 的函数赋给函数变量 f，这样调用函数变量 f 时，实际调用的就是 fire() 函数</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">   <span class="keyword">var</span> f <span class="function"><span class="keyword">func</span><span class="params">()</span></span></span><br><span class="line">   f = fire</span><br><span class="line">   f()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">fire</span><span class="params">()</span></span> &#123;</span><br><span class="line">   fmt.Println(<span class="string">&quot;fire&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="匿名函数"><a href="#匿名函数" class="headerlink" title="匿名函数"></a>匿名函数</h2><p>Go语言支持匿名函数，即在需要使用函数时再定义函数，匿名函数没有函数名只有函数体，函数可以作为一种类型被赋值给函数类型的变量，匿名函数也往往以变量方式传递，Go语言支持随时在代码里定义匿名函数。</p>
<p>匿名函数是指不需要定义函数名的一种函数实现方式，由一个不带函数名的函数声明和函数体组成。</p>
<p>匿名函数的定义格式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span><span class="params">(参数列表)</span></span>(返回参数列表)&#123;</span><br><span class="line">    函数体</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>匿名函数的定义就是没有名字的普通函数定义。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">   <span class="comment">// 匿名函数赋值给变量</span></span><br><span class="line">   f := <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">      fmt.Println(<span class="string">&quot;我是匿名函数&quot;</span>)</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">// 调用匿名函数</span></span><br><span class="line">   f()</span><br><span class="line"></span><br><span class="line">   <span class="comment">// 定义时调用</span></span><br><span class="line">   <span class="function"><span class="keyword">func</span><span class="params">(data <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">      fmt.Println(<span class="string">&quot;xuande&quot;</span>, data)</span><br><span class="line">   &#125;(<span class="number">666</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>回调函数</p>
</blockquote>
<p>根据Go语言数据类型的特点，可以将一个函数作为另外一个函数的参数</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 使用匿名函数打印切片内容</span></span><br><span class="line">	visit([]<span class="type">int</span>&#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>&#125;, <span class="function"><span class="keyword">func</span><span class="params">(v <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">		fmt.Println(v)</span><br><span class="line">	&#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 遍历切片的每个元素, 通过给定函数进行元素访问</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">visit</span><span class="params">(list []<span class="type">int</span>, f <span class="keyword">func</span>(<span class="type">int</span>)</span></span>) &#123;</span><br><span class="line">	<span class="keyword">for</span> _, v := <span class="keyword">range</span> list &#123;</span><br><span class="line">		f(v)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="defer"><a href="#defer" class="headerlink" title="defer"></a>defer</h2><p>Go语言的 defer 语句会将其后面跟随的语句进行<strong>延迟处理</strong>，在 defer 归属的函数即将返回时，将延迟处理的语句按 defer 的逆序进行执行，也就是说，先被 defer 的语句最后被执行，最后被 defer 的语句，最先被执行。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	f(<span class="string">&quot;1&quot;</span>)</span><br><span class="line">	fmt.Println(<span class="string">&quot;2&quot;</span>)</span><br><span class="line">	<span class="keyword">defer</span> f(<span class="string">&quot;3&quot;</span>)			<span class="comment">// 会被延迟到最后执行</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;4&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">f</span><span class="params">(s <span class="type">string</span>)</span></span> &#123;</span><br><span class="line">	fmt.Println(s)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>多个defer处理顺序</p>
</blockquote>
<p>当有多个 defer 行为被注册时，它们会以逆序执行（类似栈，即后进先出）</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    fmt.Println(<span class="string">&quot;defer begin&quot;</span>)</span><br><span class="line">    <span class="comment">// 将defer放入延迟调用栈</span></span><br><span class="line">    <span class="keyword">defer</span> fmt.Println(<span class="number">1</span>)</span><br><span class="line">    <span class="keyword">defer</span> fmt.Println(<span class="number">2</span>)</span><br><span class="line">    <span class="comment">// 最后一个放入, 位于栈顶, 最先调用</span></span><br><span class="line">    <span class="keyword">defer</span> fmt.Println(<span class="number">3</span>)</span><br><span class="line">    fmt.Println(<span class="string">&quot;defer end&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>解析：</p>
<ul>
<li>代码的延迟顺序与最终的执行顺序是反向的。</li>
<li>延迟调用是在 defer 所在函数结束时进行，函数结束可以是正常返回时，也可以是发生宕机时。</li>
</ul>
<blockquote>
<p>案例：对文件关闭的操作时使用defer</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">fileSize</span><span class="params">(filename <span class="type">string</span>)</span></span> <span class="type">int64</span> &#123;</span><br><span class="line">    f, err := os.Open(filename)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 延迟调用Close, 此时Close不会被调用</span></span><br><span class="line">    <span class="keyword">defer</span> f.Close()</span><br><span class="line">    info, err := f.Stat()</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="comment">// defer机制触发, 调用Close关闭文件</span></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">    size := info.Size()</span><br><span class="line">    <span class="comment">// defer机制触发, 调用Close关闭文件</span></span><br><span class="line">    <span class="keyword">return</span> size</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>recove</p>
</blockquote>
<p>Go语言的recover函数用于捕获和处理运行时异常，可以在程序中捕获到panic异常，并执行相应的处理操作，从而避免程序崩溃。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	division()</span><br><span class="line">	fmt.Println(<span class="string">&quot;上面错误已捕获，我依旧能执行&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">division</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 捕获错误并处理</span></span><br><span class="line">	<span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">		err := <span class="built_in">recover</span>()</span><br><span class="line">		<span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">			fmt.Println(<span class="string">&quot;division函数出现错误&quot;</span>, err)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;()</span><br><span class="line">	num1 := <span class="number">10</span></span><br><span class="line">	num2 := <span class="number">0</span></span><br><span class="line">	result := num1 / num2</span><br><span class="line">	fmt.Println(result)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="闭包"><a href="#闭包" class="headerlink" title="闭包"></a>闭包</h2><p>Go语言中闭包是引用了自由变量的函数，被引用的自由变量和函数一同存在，即使已经离开了自由变量的环境也不会被释放或者删除，在闭包中可以继续使用这个自由变量，因此，简单的说：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">函数 + 引用环境 = 闭包</span><br></pre></td></tr></table></figure>

<p>一个函数类型就像结构体一样，可以被实例化，函数本身不存储任何信息，只有与引用环境结合后形成的闭包才具有“记忆性”，函数是编译期静态的概念，而闭包是运行期动态的概念。</p>
<p>闭包（Closure）在某些编程语言中也被称为 Lambda 表达式。</p>
<p><strong>闭包结构中的外层函数的局部变量不会随着外层函数的结束而销毁，因为内层函数还在继续使用</strong></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	r1 := inc()		</span><br><span class="line">	fmt.Println(r1())	<span class="comment">// 1</span></span><br><span class="line">	fmt.Println(r1())	<span class="comment">// 2</span></span><br><span class="line">	fmt.Println(r1())	<span class="comment">// 3</span></span><br><span class="line">	r2 := inc()</span><br><span class="line">	fmt.Println(r2())	<span class="comment">// 1</span></span><br><span class="line">	fmt.Println(r2())	<span class="comment">// 2</span></span><br><span class="line">	fmt.Println(r1())	<span class="comment">// 4</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 自增函数</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">inc</span><span class="params">()</span></span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> <span class="type">int</span> &#123;</span><br><span class="line">	<span class="comment">// 局部变量</span></span><br><span class="line">	i := <span class="number">0</span></span><br><span class="line">	<span class="comment">// 匿名函数</span></span><br><span class="line">	fun := <span class="function"><span class="keyword">func</span><span class="params">()</span></span> <span class="type">int</span> &#123; <span class="comment">// 内层函数</span></span><br><span class="line">		i++</span><br><span class="line">		<span class="keyword">return</span> i</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> fun</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>闭包实现生成器</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">   <span class="comment">// 创建一个玩家生成器</span></span><br><span class="line">   generator := playerGen(<span class="string">&quot;xuande&quot;</span>)</span><br><span class="line">   <span class="comment">// 返回玩家的名字和血量</span></span><br><span class="line">   name, hp := generator()</span><br><span class="line">   <span class="comment">// 打印值</span></span><br><span class="line">   fmt.Println(name, hp)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个玩家生成器, 输入名称, 输出生成器</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">playerGen</span><span class="params">(name <span class="type">string</span>)</span></span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> (<span class="type">string</span>, <span class="type">int</span>) &#123;</span><br><span class="line">   <span class="comment">// 血量一直为150</span></span><br><span class="line">   hp := <span class="number">150</span></span><br><span class="line">   <span class="comment">// 返回创建的闭包</span></span><br><span class="line">   <span class="keyword">return</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> (<span class="type">string</span>, <span class="type">int</span>) &#123;</span><br><span class="line">      <span class="comment">// 将变量引用到闭包中</span></span><br><span class="line">      <span class="keyword">return</span> name, hp</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<hr>
<h1 id="容器"><a href="#容器" class="headerlink" title="容器"></a>容器</h1><p>变量在一定程度上能满足函数及代码要求。如果编写一些复杂算法、结构和逻辑，就需要更复杂的类型来实现。这类复杂类型一般情况下具有各种形式的存储和处理数据的功能，将它们称为“容器（container）”。</p>
<p>在很多语言里，容器是以标准库的方式提供，你可以随时查看这些标准库的代码，了解如何创建，删除，维护内存。</p>
<h2 id="数组（array）"><a href="#数组（array）" class="headerlink" title="数组（array）"></a>数组（array）</h2><p>数组是一个由固定长度的特定类型元素组成的序列，一个数组可以由零个或多个元素组成。因为数组的长度是固定的，所以在Go语言中很少直接使用数组（数组是值传递）。</p>
<h3 id="数组的定义"><a href="#数组的定义" class="headerlink" title="数组的定义"></a>数组的定义</h3><p>数组定义格式如下</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> 数组变量名 [元素数量]Type</span><br></pre></td></tr></table></figure>

<p>语法说明如下所示：</p>
<ul>
<li>数组变量名：数组声明及使用时的变量名。</li>
<li>元素数量：数组的元素数量，可以是一个表达式，但最终通过编译期计算的结果必须是整型数值，元素数量不能含有到运行时才能确认大小的数值。</li>
<li>Type：可以是任意基本类型，包括数组本身，类型为数组本身时，可以实现多维数组。</li>
</ul>
<p>数组的每个元素都可以通过索引下标来访问，索引下标的范围是从 0 开始到数组长度减 1 的位置，内置函数 len() 可以返回数组中元素的个数。</p>
<p>默认情况下，数组的每个元素都会被初始化为元素类型对应的零值，对于数字类型来说就是 0</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 定义数组，默认为对应元素的零值</span></span><br><span class="line">	<span class="keyword">var</span> a [<span class="number">3</span>]<span class="type">int</span></span><br><span class="line">    <span class="comment">// 仅打印元素</span></span><br><span class="line">	<span class="keyword">for</span> _, v := <span class="keyword">range</span> a &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;未赋值，元素：%d\n&quot;</span>, v)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 数组赋值</span></span><br><span class="line">	a = [<span class="number">3</span>]<span class="type">int</span>&#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>&#125;</span><br><span class="line">	<span class="comment">// 打印索引和元素</span></span><br><span class="line">	<span class="keyword">for</span> i, v := <span class="keyword">range</span> a &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;索引：%d，元素：%d\n&quot;</span>, i, v)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 仅打印元素</span></span><br><span class="line">	<span class="keyword">for</span> _, v := <span class="keyword">range</span> a &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;元素：%d\n&quot;</span>, v)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>使用”…”省略号，表示数组的长度是根据初始化值的个数来计算</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	q := [...]<span class="type">int</span>&#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>&#125;</span><br><span class="line">	fmt.Printf(<span class="string">&quot;%T\n&quot;</span>, q) <span class="comment">// &quot;[3]int&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="多维数组"><a href="#多维数组" class="headerlink" title="多维数组"></a>多维数组</h3><p>Go语言中允许使用多维数组，因为数组属于值类型，所以多维数组的所有维度都会在创建时自动初始化零值，多维数组尤其适合管理具有父子关系或者与坐标系相关联的数据。</p>
<p> 声明多维数组的语法如下所示：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> 多维数组变量名 [每一维度的长度][每一维度的长度]...[每一维度的长度] 数组类型</span><br></pre></td></tr></table></figure>

<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 声明一个二维整型数组，两个维度的长度分别是 4 和 2</span></span><br><span class="line">	<span class="keyword">var</span> array [<span class="number">4</span>][<span class="number">2</span>]<span class="type">int</span></span><br><span class="line">	<span class="comment">// 使用数组字面量来声明并初始化一个二维整型数组</span></span><br><span class="line">	array = [<span class="number">4</span>][<span class="number">2</span>]<span class="type">int</span>&#123;&#123;<span class="number">10</span>, <span class="number">11</span>&#125;, &#123;<span class="number">20</span>, <span class="number">21</span>&#125;, &#123;<span class="number">30</span>, <span class="number">31</span>&#125;, &#123;<span class="number">40</span>, <span class="number">41</span>&#125;&#125;</span><br><span class="line">	<span class="comment">// 打印二维数组</span></span><br><span class="line">	<span class="keyword">for</span> i := <span class="keyword">range</span> array &#123;</span><br><span class="line">		<span class="keyword">for</span> _, j := <span class="keyword">range</span> array[i] &#123;</span><br><span class="line">			<span class="built_in">println</span>(j)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="切片（slice）"><a href="#切片（slice）" class="headerlink" title="切片（slice）"></a>切片（slice）</h2><p>数组虽然有特定的用处，但因为数组的长度固定不变，这就显得有些呆，所以Go语言就有一种特殊的数据类型<strong>切片（slice）</strong></p>
<p>切片默认指向一段连续内存区域，可以是数组，也可以是切片本身，另外切片是可以<strong>动态增长</strong>的。</p>
<p>切片是对数组的一个连续片段的引用，所以切片是一个引用类型，这个片段可以是整个数组，也可以是由起始和终止索引标识的一些项的子集，需要注意的是，终止索引标识的项不包括在切片内。切片提供了一个相关数组的动态窗口</p>
<p>由于切片是对数组的一个连续片段的引用，所以切片有3个字段的数据结构：</p>
<ul>
<li>指向底层数组的指针</li>
<li>切片的长度</li>
<li>切片的容量</li>
</ul>
<h3 id="切片的定义"><a href="#切片的定义" class="headerlink" title="切片的定义"></a>切片的定义</h3><blockquote>
<p>从数组或切片生成新的切片</p>
</blockquote>
<p>从连续内存区域生成切片是常见的操作</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">slice [开始位置 : 结束位置]</span><br></pre></td></tr></table></figure>

<p>语法说明如下：</p>
<ul>
<li>slice：表示目标切片对象；</li>
<li>开始位置：对应目标切片对象的索引；</li>
<li>结束位置：对应目标切片的结束索引。</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 定义数组</span></span><br><span class="line">	<span class="keyword">var</span> arr = [<span class="number">6</span>]<span class="type">int</span>&#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>&#125;</span><br><span class="line">	<span class="comment">// 从数组切片（左闭右开）</span></span><br><span class="line">	slice := arr[<span class="number">1</span>:<span class="number">3</span>]</span><br><span class="line">	<span class="comment">// 打印数组</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;arr：&quot;</span>, arr) 						  <span class="comment">// arr： [1 2 3 4 5 6]</span></span><br><span class="line">	<span class="comment">// 打印切片</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;slice：&quot;</span>, slice) 					  <span class="comment">// slice： [2 3]</span></span><br><span class="line">	<span class="comment">// 切片的元素个数</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;切片的元素个数：&quot;</span>, <span class="built_in">len</span>(slice)) 		  <span class="comment">// 2</span></span><br><span class="line">	<span class="comment">// 获取切片的容量，容量可以动态变化</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;切片的容量：&quot;</span>, <span class="built_in">cap</span>(slice)) 		 	   <span class="comment">// 5</span></span><br><span class="line">    fmt.Printf(<span class="string">&quot;数组中下标为1的地址：%p：\n&quot;</span>, &amp;arr[<span class="number">1</span>])		<span class="comment">// 0xc0000c8038</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;切片中下标为0的地址：%p：\n&quot;</span>, &amp;slice[<span class="number">0</span>])	<span class="comment">// 0xc0000c8038</span></span><br><span class="line">	slice[<span class="number">1</span>] = <span class="number">66</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;arr：&quot;</span>, arr)     					  <span class="comment">// arr： [1 2 66 4 5 6]</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;slice：&quot;</span>, slice) 					  <span class="comment">// slice： [2 66]</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>make()函数构造切片</p>
</blockquote>
<p>如果需要动态地创建一个切片，可以使用 make() 内建函数，格式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">make</span>( []Type, size, <span class="built_in">cap</span> )</span><br></pre></td></tr></table></figure>

<p>语法说明如下：</p>
<ul>
<li>Type：切片类型</li>
<li>size：  切片长度</li>
<li>cap：  切片容量，不影响 size，主要目的是降低多次分配空间而造成的性能问题。</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	slice := <span class="built_in">make</span>([]<span class="type">int</span>, <span class="number">6</span>, <span class="number">10</span>)</span><br><span class="line">	fmt.Println(slice)               	<span class="comment">// [0 0 0 0 0 0]</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;切片长度：&quot;</span>, <span class="built_in">len</span>(slice)) <span class="comment">// 切片长度： 6</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;切片容量：&quot;</span>, <span class="built_in">cap</span>(slice)) <span class="comment">// 切片容量： 10</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>注：make底层维护一个数组，但是这个数组对外不可见，无法操作这个数组</strong></p>
<blockquote>
<p>直接声明新的切片</p>
</blockquote>
<p>定义一个切片，直接指定具体的数组，原理类似make()</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	slice := []<span class="type">int</span>&#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>&#125;</span><br><span class="line">	fmt.Println(slice)               	<span class="comment">// [1 2 3 4 5 6]</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;切片长度：&quot;</span>, <span class="built_in">len</span>(slice)) <span class="comment">// 切片长度： 6</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;切片容量：&quot;</span>, <span class="built_in">cap</span>(slice)) <span class="comment">// 切片容量： 6</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="追加函数"><a href="#追加函数" class="headerlink" title="追加函数"></a>追加函数</h3><p>Go语言的内置函数 append() 可以为切片动态添加元素</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> slice []<span class="type">int</span></span><br><span class="line">	slice = <span class="built_in">append</span>(slice, <span class="number">1</span>) <span class="comment">// 追加1个元素</span></span><br><span class="line">	fmt.Println(slice)	<span class="comment">// [1]</span></span><br><span class="line">	slice = <span class="built_in">append</span>(slice, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>) <span class="comment">// 追加多个元素, 手写解包方式</span></span><br><span class="line">	fmt.Println(slice)	<span class="comment">// [1 1 2 3]</span></span><br><span class="line">	slice = <span class="built_in">append</span>(slice, []<span class="type">int</span>&#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>&#125;...) <span class="comment">// 追加一个切片, 切片需要解包</span></span><br><span class="line">	fmt.Println(slice)  <span class="comment">// [1 1 2 3 1 2 3]</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>切片的扩容机制</p>
</blockquote>
<p>在添加元素时，如果空间不足，切片就会进行扩容，此时切片长度将会发生改变，扩容的规律是按容量的 2 倍数进行扩容</p>
<p>扩容原理：</p>
<ul>
<li>创建一个新数组，将老数组的值复制到新数组中</li>
<li>在新数组中追加值</li>
<li>底层指针由指向老数组改为指向新数组</li>
<li>底层的新数组不能直接维护，需要通过切片间接维护</li>
</ul>
<h2 id="列表（list）"><a href="#列表（list）" class="headerlink" title="列表（list）"></a>列表（list）</h2><p>列表是一种非连续的存储容器，由多个节点组成，节点通过一些变量记录彼此之间的关系，列表有多种实现方法，如单链表、双链表等。</p>
<p>在Go语言中，列表使用 container&#x2F;list 包来实现，内部的实现原理是<strong>双链表</strong>，列表能够高效地进行任意位置的元素插入和删除操作。</p>
<h3 id="列表的定义"><a href="#列表的定义" class="headerlink" title="列表的定义"></a>列表的定义</h3><p>列表定义格式如下：</p>
<ol>
<li><p>通过 container&#x2F;list 包的 New() 函数初始化 list</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">变量名 := list.New()</span><br></pre></td></tr></table></figure>
</li>
<li><p>通过 var 关键字声明初始化 list</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var 变量名 list.List</span><br></pre></td></tr></table></figure></li>
</ol>
<p>列表没有具体元素类型的限制，因此，列表的元素可以是任意类型，但这既带来了便利，也引来一些问题，例如转换某种特定的类型时将会发生宕机。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">   <span class="comment">// 创建一个列表</span></span><br><span class="line">   l := list.New()</span><br><span class="line">   <span class="comment">// 插入列表尾部</span></span><br><span class="line">   l.PushBack(<span class="string">&quot;first&quot;</span>)</span><br><span class="line">   l.PushBack(<span class="string">&quot;second&quot;</span>)</span><br><span class="line">   <span class="comment">// 插入列表头部</span></span><br><span class="line">   l.PushFront(<span class="string">&quot;head&quot;</span>)</span><br><span class="line">   <span class="comment">// 遍历列表</span></span><br><span class="line">   <span class="keyword">for</span> i := l.Front(); i != <span class="literal">nil</span>; i = i.Next() &#123;</span><br><span class="line">      fmt.Println(i.Value)			<span class="comment">// head first second</span></span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="从列表中删除元素"><a href="#从列表中删除元素" class="headerlink" title="从列表中删除元素"></a>从列表中删除元素</h3><p>列表插入函数的返回值会提供一个 *list.Element 结构，这个结构记录着列表元素的值以及与其他节点之间的关系等信息，从列表中删除元素时，需要用到这个结构进行快速删除。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 创建一个列表</span></span><br><span class="line">	l := list.New()</span><br><span class="line">	<span class="comment">// 尾部添加后保存元素句柄</span></span><br><span class="line">	element := l.PushBack(<span class="string">&quot;first&quot;</span>)</span><br><span class="line">	<span class="comment">// 在fist之后添加second</span></span><br><span class="line">	l.InsertAfter(<span class="string">&quot;second&quot;</span>, element)</span><br><span class="line">	<span class="comment">// 在fist之前添加head</span></span><br><span class="line">	l.InsertBefore(<span class="string">&quot;head&quot;</span>, element)</span><br><span class="line">	<span class="built_in">println</span>(<span class="string">&quot;删除前：&quot;</span>)</span><br><span class="line">	<span class="comment">// 遍历列表</span></span><br><span class="line">	<span class="keyword">for</span> i := l.Front(); i != <span class="literal">nil</span>; i = i.Next() &#123;</span><br><span class="line">		fmt.Println(i.Value)		<span class="comment">// head first second</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 删除first元素</span></span><br><span class="line">	l.Remove(element)</span><br><span class="line">	<span class="built_in">println</span>(<span class="string">&quot;删除后：&quot;</span>)</span><br><span class="line">	<span class="comment">// 遍历列表</span></span><br><span class="line">	<span class="keyword">for</span> i := l.Front(); i != <span class="literal">nil</span>; i = i.Next() &#123;</span><br><span class="line">		fmt.Println(i.Value)		<span class="comment">// head second</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="映射（map）"><a href="#映射（map）" class="headerlink" title="映射（map）"></a>映射（map）</h2><p>映射（map）是一种特殊的数据结构，它内置在Go语言中 ，它有一个 key（索引）和一个 value（值），我们将它成为键值对，所以这个结构也称为关联数组或字典，这是一种能够快速寻找值的理想结构，给定 key，就可以迅速找到对应的 value。</p>
<p>map 这种数据结构在其他编程语言中也称为字典（Python）、hashmap（Java）</p>
<h3 id="映射的定义"><a href="#映射的定义" class="headerlink" title="映射的定义"></a>映射的定义</h3><p>map 是引用类型，它的声明方式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> mapname <span class="keyword">map</span>[keytype]valuetype</span><br></pre></td></tr></table></figure>

<p>语法说明如下：</p>
<ul>
<li>mapname 为 map 的变量名。</li>
<li>keytype 为键类型。</li>
<li>valuetype 是键对应的值类型。</li>
</ul>
<p>在声明的时候不需要知道 map 的长度，因为 map 是可以动态增长的，未初始化的 map 的值是 nil，使用函数 len() 可以获取 map 中 pair 的数目。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 定义map变量</span></span><br><span class="line">	<span class="keyword">var</span> m <span class="keyword">map</span>[<span class="type">string</span>]<span class="type">string</span></span><br><span class="line">	<span class="comment">// 只声明map内存是没有分配空间的</span></span><br><span class="line">	<span class="comment">// 必须通过make函数进行初始化，才会分配空间，map的长度可以动态增长</span></span><br><span class="line">	m = <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">string</span>]<span class="type">string</span>, <span class="number">10</span>)</span><br><span class="line">	<span class="comment">// 键值对存入map</span></span><br><span class="line">	m[<span class="string">&quot;key1&quot;</span>] = <span class="string">&quot;张三&quot;</span></span><br><span class="line">	m[<span class="string">&quot;key2&quot;</span>] = <span class="string">&quot;李四&quot;</span></span><br><span class="line">	m[<span class="string">&quot;key3&quot;</span>] = <span class="string">&quot;王五&quot;</span></span><br><span class="line">	<span class="comment">// 输出集合</span></span><br><span class="line">	fmt.Println(m) 		<span class="comment">// map[key1:张三 key2:李四 key3:王五]</span></span><br><span class="line">	m[<span class="string">&quot;key1&quot;</span>] = <span class="string">&quot;阿巴阿巴阿巴&quot;</span></span><br><span class="line">	<span class="comment">// 重复的key将会被覆盖</span></span><br><span class="line">	fmt.Println(m) 		<span class="comment">// map[key1:阿巴阿巴阿巴 key2:李四 key3:王五]</span></span><br><span class="line">	<span class="comment">// value可以重复</span></span><br><span class="line">	m[<span class="string">&quot;key4&quot;</span>] = <span class="string">&quot;李四&quot;</span></span><br><span class="line">	fmt.Println(m) 		<span class="comment">// map[key1:阿巴阿巴阿巴 key2:李四 key3:王五 key4:李四]</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>使用map的注意事项：</p>
<ul>
<li>map使用前一定要make</li>
<li>map的key-value是无序的</li>
<li>key不可以重复，重复会被最后一个value覆盖</li>
<li>value是可以重复的</li>
</ul>
<h3 id="map的容量"><a href="#map的容量" class="headerlink" title="map的容量"></a>map的容量</h3><p>与数组不同，map 可以根据新增的 key-value 动态的扩容，因此它不存在固定长度或者最大限制，但是也可以选择标明 map 的初始容量 capacity，如果不标明cap，它将默认分配一个内存空间</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">make</span>(<span class="keyword">map</span>[keytype]valuetype, <span class="built_in">cap</span>)</span><br></pre></td></tr></table></figure>

<p>当 map 增长到容量上限的时候，如果再增加新的 key-value，map 的大小会自动加 1，所以出于性能的考虑，对于大的 map 或者会快速扩张的 map，即使只是大概知道容量，也最好先标明。</p>
<h3 id="操作map"><a href="#操作map" class="headerlink" title="操作map"></a>操作map</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 定义map</span></span><br><span class="line">	m := <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">string</span>]<span class="type">string</span>)</span><br><span class="line">	<span class="comment">// 增</span></span><br><span class="line">	m[<span class="string">&quot;k1&quot;</span>] = <span class="string">&quot;v1&quot;</span></span><br><span class="line">	m[<span class="string">&quot;k2&quot;</span>] = <span class="string">&quot;v2&quot;</span></span><br><span class="line">	m[<span class="string">&quot;k3&quot;</span>] = <span class="string">&quot;v3&quot;</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;增：&quot;</span>, m)</span><br><span class="line">	<span class="comment">// 删</span></span><br><span class="line">	<span class="built_in">delete</span>(m, <span class="string">&quot;k3&quot;</span>)</span><br><span class="line">	fmt.Println(<span class="string">&quot;删：&quot;</span>, m)</span><br><span class="line">	<span class="comment">// 改</span></span><br><span class="line">	m[<span class="string">&quot;k2&quot;</span>] = <span class="string">&quot;vv2&quot;</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;改：&quot;</span>, m)</span><br><span class="line">	<span class="comment">// 查</span></span><br><span class="line">	value, flag := m[<span class="string">&quot;k2&quot;</span>]</span><br><span class="line">	fmt.Println(<span class="string">&quot;查：&quot;</span>, m)</span><br><span class="line">	fmt.Println(value)</span><br><span class="line">	fmt.Println(flag)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>遍历map</p>
</blockquote>
<p>map的遍历只能用for-range循环</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	scene := <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">string</span>]<span class="type">int</span>)</span><br><span class="line">	scene[<span class="string">&quot;route&quot;</span>] = <span class="number">66</span></span><br><span class="line">	scene[<span class="string">&quot;brazil&quot;</span>] = <span class="number">4</span></span><br><span class="line">	scene[<span class="string">&quot;china&quot;</span>] = <span class="number">960</span></span><br><span class="line">	<span class="keyword">for</span> k, v := <span class="keyword">range</span> scene &#123;</span><br><span class="line">		fmt.Println(k, v)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>map的清空机制</p>
</blockquote>
<p>Go语言中并没有为 map 提供任何清空所有元素的函数、方法，清空 map 的唯一办法就是重新 make 一个新的 map，不过不用担心垃圾回收的效率，Go语言中的并行垃圾回收效率比写一个清空函数要高效的多。</p>
<hr>
<h1 id="面向对象"><a href="#面向对象" class="headerlink" title="面向对象"></a>面向对象</h1><p>Go语言也支持面向对象编程（OOP），但它和传统的面向对象编程有些许区别，并不是纯粹的面向对象语言。</p>
<p>Go 语言中的类型可以被实例化，使用<code>new</code>或<code>&amp;</code>构造的类型实例的类型是类型的指针。</p>
<p>Go语言中并没有类（class），但它的<strong>结构体（struct）</strong>和其他编程语言的类有同等的地位，结构体的内嵌配合接口比面向对象具有更高的扩展性和灵活性，结构体不仅能拥有方法，而且每种自定义类型也可以拥有自己的方法。</p>
<h2 id="结构体"><a href="#结构体" class="headerlink" title="结构体"></a>结构体</h2><p>Go语言可以通过自定义的方式形成新的类型，结构体就是这些类型中的一种复合类型，结构体是由零个或多个任意类型的值聚合成的实体，每个值都可以称为结构体的成员。</p>
<p>Go语言的结构体和Java中的类有相同的地位，甚至比java中的类更灵活</p>
<h3 id="结构体定义"><a href="#结构体定义" class="headerlink" title="结构体定义"></a>结构体定义</h3><p>结构体成员也可以称为“字段”，这些字段有以下特性：</p>
<ul>
<li>字段拥有自己的类型和值；</li>
<li>字段名必须唯一；</li>
<li>字段的类型也可以是结构体，甚至是字段所在结构体的类型。</li>
</ul>
<p>使用关键字 <strong>type</strong> 可以将各种基本类型定义为自定义类型，基本类型包括整型、字符串、布尔等。结构体是一种复合的基本类型，通过 type 定义为自定义类型后，使结构体更便于使用。</p>
<p>结构体的声明方式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> 类型名 <span class="keyword">struct</span> &#123;</span><br><span class="line">    字段<span class="number">1</span> 字段<span class="number">1</span>类型</span><br><span class="line">    字段<span class="number">2</span> 字段<span class="number">2</span>类型</span><br><span class="line">    …</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>语法说明如下：</p>
<ul>
<li>类型名：标识自定义结构体的名称，在同一个包内不能重复。</li>
<li>struct{}：表示结构体类型，<code>type 类型名 struct&#123;&#125;</code>可以理解为将 struct{} 结构体定义为类型名的类型。</li>
<li>字段1、字段2……：表示结构体字段名，结构体中的字段名必须唯一。</li>
<li>字段1类型、字段2类型……：表示结构体各个字段的类型。</li>
</ul>
<p><strong>结构体的定义只是一种内存布局的描述，只有当结构体实例化时，才会真正地分配内存</strong></p>
<h3 id="结构体实例"><a href="#结构体实例" class="headerlink" title="结构体实例"></a>结构体实例</h3><p>结构体必须在定义并实例化后才能使用结构体的字段。</p>
<p>实例化就是根据结构体定义的格式创建一份与格式一致的内存区域，结构体各个实例间的内存是完全独立的。</p>
<blockquote>
<p>基本的实例化方式</p>
</blockquote>
<p>基本实例化格式如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var 实例 结构体类型</span><br></pre></td></tr></table></figure>

<p>这是最常见的实例化方式，直接创建</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Student 定义学生结构体，将学生的各个属性统一放到结构体中管理</span></span><br><span class="line"><span class="keyword">type</span> Student <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name   <span class="type">string</span></span><br><span class="line">	Age    <span class="type">int</span></span><br><span class="line">	School <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 创建学生结构体实例</span></span><br><span class="line">	<span class="keyword">var</span> s Student</span><br><span class="line">	<span class="comment">// 结构体赋值，使用点（.）来访问结构体的成员变量</span></span><br><span class="line">	s.Name = <span class="string">&quot;玄德&quot;</span></span><br><span class="line">	s.Age = <span class="number">20</span></span><br><span class="line">	s.School = <span class="string">&quot;清北幼儿园&quot;</span></span><br><span class="line">	fmt.Println(s)		<span class="comment">// &#123;玄德 20 清北幼儿园&#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>创建指针结构体</p>
</blockquote>
<p>Go语言中，还可以使用 new 关键字对类型进行实例化，结构体在实例化后会形成指针类型的结构体。</p>
<p>创建格式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> 实例 结构体指针 = <span class="built_in">new</span>(结构体)</span><br><span class="line"><span class="comment">// 也可以简写</span></span><br><span class="line">实例 := <span class="built_in">new</span>(结构体)</span><br></pre></td></tr></table></figure>

<p>Go语言让我们可以像访问普通结构体一样使用<code>.</code>来访问结构体指针的成员，这是因为Go语言为了方便开发者访问结构体指针的成员变量，使用了语法糖，将 s.Name 形式转换为 (*s).Name。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Student 定义学生结构体，将学生的各个属性统一放到结构体中管理</span></span><br><span class="line"><span class="keyword">type</span> Student <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name   <span class="type">string</span></span><br><span class="line">	Age    <span class="type">int</span></span><br><span class="line">	School <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 创建学生结构体实例</span></span><br><span class="line">	s := <span class="built_in">new</span>(Student)</span><br><span class="line">	<span class="comment">// 实例s 其实是指针 *s，s指向的是地址</span></span><br><span class="line">	(*s).Name = <span class="string">&quot;玄德&quot;</span></span><br><span class="line">	<span class="comment">// 因为go语言的语法糖，简化了赋值方式，可以直接使用.</span></span><br><span class="line">	s.Age = <span class="number">20</span></span><br><span class="line">	s.School = <span class="string">&quot;清华幼儿园&quot;</span></span><br><span class="line">	fmt.Println(s) <span class="comment">// &amp;&#123;玄德 20 清华幼儿园&#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>结构体的地址实例化</p>
</blockquote>
<p>在Go语言中，对结构体进行<code>&amp;</code>取地址操作时，视为对该类型进行一次 new 的实例化操作</p>
<p>取地址实例化是最广泛的一种结构体实例化方式，可以使用函数封装上面的初始化过程</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Student 定义学生结构体，将学生的各个属性统一放到结构体中管理</span></span><br><span class="line"><span class="keyword">type</span> Student <span class="keyword">struct</span> &#123;</span><br><span class="line">   Name   <span class="type">string</span></span><br><span class="line">   Age    <span class="type">int</span></span><br><span class="line">   School <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">   <span class="comment">// 创建学生结构体实例</span></span><br><span class="line">   s := &amp;Student&#123;School: <span class="string">&quot;清华幼儿园&quot;</span>&#125;</span><br><span class="line">   (*s).Name = <span class="string">&quot;玄德&quot;</span></span><br><span class="line">   s.Age = <span class="number">20</span></span><br><span class="line">   fmt.Println(s) <span class="comment">// &amp;&#123;玄德 20 清华幼儿园&#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="结构体之间的转换"><a href="#结构体之间的转换" class="headerlink" title="结构体之间的转换"></a>结构体之间的转换</h3><p>结构体是单独定义的类型，和其他类型转换时需要有完全相同的字段，转换时还需加上结构体类型</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Student <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Person <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	s := &amp;Student&#123;<span class="string">&quot;&quot;</span>&#125;</span><br><span class="line">	p := &amp;Person&#123;Name: <span class="string">&quot;玄德&quot;</span>&#125;</span><br><span class="line">	s = (*Student)(p)</span><br><span class="line">	fmt.Println(s) <span class="comment">// &amp;&#123;玄德&#125;</span></span><br><span class="line">	fmt.Println(p) <span class="comment">// &amp;&#123;玄德&#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>结构体进行type重新定义（相当于取别名），Golang认为这是新的数据类型，但是相互间可以强转</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Student <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Stu Student</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	s1 := &amp;Student&#123;<span class="string">&quot;&quot;</span>&#125;</span><br><span class="line">	s2 := &amp;Stu&#123;Name: <span class="string">&quot;玄德&quot;</span>&#125;</span><br><span class="line">	s1 = (*Student)(s2)</span><br><span class="line">	fmt.Println(s1) <span class="comment">// &amp;&#123;玄德&#125;</span></span><br><span class="line">	fmt.Println(s2) <span class="comment">// &amp;&#123;玄德&#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h2><p>Go语言的方法是作用在指定的数据类型上，和指定的数据类型相互绑定，因此<strong>自定义类型，都可以有方法</strong>，而不仅仅是struct</p>
<h3 id="方法的定义"><a href="#方法的定义" class="headerlink" title="方法的定义"></a>方法的定义</h3><p>方法的声明方式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> A <span class="keyword">struct</span> &#123;</span><br><span class="line">    字段 字段类型</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(a A)</span></span> 方法名() &#123;</span><br><span class="line">	方法体</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>方法和函数的定义类似，但方法需要传递结构体的类型</p>
<p><code>func (a A) 方法名()</code> 相当于A结构体有一个test方法，<strong>方法和结构体需要有绑定关系</strong></p>
<p>由于结构体类型是值传递，所以方法的传递也是值传递，因此方法遵守值类型的传递机制，值拷贝传递</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义Person结构体</span></span><br><span class="line"><span class="keyword">type</span> Person <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 给Person结构体绑定test方法</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(p Person)</span></span> test() &#123;</span><br><span class="line">	fmt.Println(p.Name)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 创建结构体对象</span></span><br><span class="line">	<span class="keyword">var</span> p Person</span><br><span class="line">	p.Name = <span class="string">&quot;玄德&quot;</span></span><br><span class="line">	p.test()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果希望在方法中，改变结构体变量的值，可以通过结构体指针的方式来处理</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义Person结构体</span></span><br><span class="line"><span class="keyword">type</span> Person <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 给Person结构体绑定test方法</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(p *Person)</span></span> test() &#123;</span><br><span class="line">    p.Name = <span class="string">&quot;阿巴阿巴&quot;</span>		<span class="comment">// 已简化，实际为(*p)</span></span><br><span class="line">	fmt.Println(p.Name)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 创建结构体对象</span></span><br><span class="line">	<span class="keyword">var</span> p Person</span><br><span class="line">	p.Name = <span class="string">&quot;玄德&quot;</span>		 <span class="comment">// 已简化，实际为(&amp;p)</span></span><br><span class="line">	p.test()</span><br><span class="line">	fmt.Println(p.Name)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>方法访问规则</p>
</blockquote>
<p><strong>方法名首字母小写，只能在本包访问，方法名首字母大写，可以在本包和其他包访问</strong></p>
<h3 id="自定义类型方法"><a href="#自定义类型方法" class="headerlink" title="自定义类型方法"></a>自定义类型方法</h3><p>Go语言中的方法作用在指定的数据类型上，和指定的数据类型绑定，因此<strong>自定义类型，都可以有方法</strong>，不仅仅是结构体</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> integer <span class="type">int</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(i integer)</span></span> <span class="built_in">print</span>() &#123;</span><br><span class="line">	i = <span class="number">60</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;i = &quot;</span>, i)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(i *integer)</span></span> change() &#123;</span><br><span class="line">	*i = <span class="number">60</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;i = &quot;</span>, *i)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> i integer = <span class="number">30</span></span><br><span class="line">	i.<span class="built_in">print</span>()</span><br><span class="line">	fmt.Println(i)</span><br><span class="line">	i.change()</span><br><span class="line">	fmt.Println(i)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="方法和函数的区别"><a href="#方法和函数的区别" class="headerlink" title="方法和函数的区别"></a>方法和函数的区别</h3><p>方法：</p>
<ul>
<li>需要绑定指定的数据类型</li>
<li>方法的调用是变量.方法名（实参列表）</li>
<li>因为编译器做了处理，所以指针类型和值类型都可以传入和接收</li>
</ul>
<p>函数：</p>
<ul>
<li>不需要绑定数据类型</li>
<li>函数的调用是函数名（实参列表）</li>
<li>参数类型是什么就要传入什么</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Student <span class="keyword">struct</span> &#123;</span><br><span class="line">   Name <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义方法</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(s *Student)</span></span> test01() &#123;</span><br><span class="line">   fmt.Println(s.Name)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(s *Student)</span></span> test02() &#123;</span><br><span class="line">   fmt.Println(s.Name)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义函数</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">method01</span><span class="params">(s Student)</span></span> &#123;</span><br><span class="line">   fmt.Println(s.Name)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">method02</span><span class="params">(s *Student)</span></span> &#123;</span><br><span class="line">   fmt.Println(s.Name)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">   <span class="keyword">var</span> s = Student&#123;<span class="string">&quot;玄德&quot;</span>&#125;</span><br><span class="line">   <span class="comment">// 调用函数</span></span><br><span class="line">   method01(s)  <span class="comment">// method01(&amp;s)报错</span></span><br><span class="line">   method02(&amp;s) <span class="comment">// method02(s)报错</span></span><br><span class="line">   <span class="built_in">println</span>(<span class="string">&quot;----------------分界线------------------&quot;</span>)</span><br><span class="line">   <span class="comment">// 调用方法</span></span><br><span class="line">   s.test01()</span><br><span class="line">   (&amp;s).test01() <span class="comment">// 虽然是指针类型调用，但传递还是值传递</span></span><br><span class="line">   s.test02()    <span class="comment">// 编译器做了处理，所以等价下面的语句</span></span><br><span class="line">   (&amp;s).test02()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="封装"><a href="#封装" class="headerlink" title="封装"></a>封装</h2><h3 id="封装的定义"><a href="#封装的定义" class="headerlink" title="封装的定义"></a>封装的定义</h3><p>封装(encapsulation)是把抽象出来的的字段和对字段的操作封装在一起，数据被保护在内部，程序的其他包只有通过被授权的操作方法，才能对字段进行操作 </p>
<p>在程序设计的过程中要追求“高内聚，低耦合”。</p>
<p>高内聚：类的内部数据操作细节自己来完成，不允许外部干涉</p>
<p>低耦合：仅暴露少量的方法给外部使用</p>
<p>而封装，就是禁止直接访问一个对象中的数据，而是应该通过操作接口来访问，大白话就是该露的露，该藏的藏，你要访问必须经过我设置的规矩（方法），否则你就动不了它（字段）</p>
<h3 id="实现封装"><a href="#实现封装" class="headerlink" title="实现封装"></a>实现封装</h3><ul>
<li>将结构体、 字段(属性)的首字母小写(让其它包不能使用，类似private，但不小写也有可能，因为go语言封装不那么严格)</li>
<li>给结构体所在包提供一个工厂模式的函数，首字母大写（类似一个构造函数）</li>
<li>提供一个首字母大写的Set方法(类似其它语言的public)，用于对属性判断并赋值</li>
<li>提供一个首字母大写的Get方法(类似其它语言的public)，用于获取属性的值</li>
</ul>
<blockquote>
<p>代码实现</p>
</blockquote>
<p>目录结构：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">├─test                       </span><br><span class="line">│  └─src               </span><br><span class="line">│      └─main             </span><br><span class="line">│			└─go</span><br><span class="line">│				└─model</span><br><span class="line">│					└─person.go</span><br><span class="line">│				test.go</span><br></pre></td></tr></table></figure>

<p>person.go</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> model</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> person <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">	age  <span class="type">int</span> <span class="comment">// 首字母小写，其他包不能直接访问</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义工厂模式的函数，相当于其他语言的构造器</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewPerson</span><span class="params">(name <span class="type">string</span>)</span></span> *person &#123;</span><br><span class="line">	<span class="keyword">return</span> &amp;person&#123;</span><br><span class="line">		Name: name,</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义set和get方法，对age字段进行封装，因为在方法中可以定义一系列的限制操作，确保封装字段的安全合理性</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(p *person)</span></span> SetAge(age <span class="type">int</span>) &#123;</span><br><span class="line">	<span class="keyword">if</span> age &gt; <span class="number">0</span> &amp;&amp; age &lt; <span class="number">150</span> &#123;</span><br><span class="line">		p.age = age</span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;请输入正确的年龄&quot;</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(p *person)</span></span> GetAge() <span class="type">int</span> &#123;</span><br><span class="line">	<span class="keyword">return</span> p.age</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>main.go</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;Test/src/main/go/model&quot;</span></span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 创建person结构体</span></span><br><span class="line">	p := model.NewPerson(<span class="string">&quot;玄德&quot;</span>)</span><br><span class="line">	p.SetAge(<span class="number">20</span>)</span><br><span class="line"></span><br><span class="line">	fmt.Println(p.Name)     <span class="comment">// 玄德</span></span><br><span class="line">	fmt.Println(p.GetAge()) <span class="comment">// 20</span></span><br><span class="line">	fmt.Println(*p)         <span class="comment">// 玄德</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h2><h3 id="继承的定义"><a href="#继承的定义" class="headerlink" title="继承的定义"></a>继承的定义</h3><p>Go语言中的继承是通过<strong>内嵌或组合</strong>来实现的，当多个结构体存在相同的属性（字段）和方法时，可以从这些结构体中抽象出相同的部分重新定义一个新的结构体：<strong>匿名结构体</strong>，在这个匿名结构体中包含它们重合的属性和方法，其它的结构体不需要重新定义这些属性和方法，只需要嵌套一个匿名结构体即可。</p>
<h3 id="继承的实现"><a href="#继承的实现" class="headerlink" title="继承的实现"></a>继承的实现</h3><p>在Go语言中，<strong>如果一个struct嵌套了另一个匿名结构体，那么这个结构体可以直接访问匿名结构体的字段和方法</strong>，从而实现继承的特性</p>
<ul>
<li>要实现继承，必须内嵌匿名结构体</li>
<li>结构体内嵌后可以使用匿名结构体的所有字段和方法，并且没有大小写限制</li>
<li>匿名结构体字段和方法的访问可以简化</li>
<li>结构体的匿名字段可以是基本数据类型</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义动物结构体</span></span><br><span class="line"><span class="keyword">type</span> Animal <span class="keyword">struct</span> &#123;</span><br><span class="line">	Age    <span class="type">int</span></span><br><span class="line">	Weight <span class="type">float64</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 给Animal绑定方法</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(a *Animal)</span></span> Shout() &#123;</span><br><span class="line">	fmt.Print(<span class="string">&quot;现在我要说话了：&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(a *Animal)</span></span> ShowInfo() &#123;</span><br><span class="line">	fmt.Printf(<span class="string">&quot;我的年龄是：%v岁，体重是：%vkg\n&quot;</span>, a.Age, a.Weight)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义结构体Cat</span></span><br><span class="line"><span class="keyword">type</span> Cat <span class="keyword">struct</span> &#123;</span><br><span class="line">	<span class="comment">// 为了复用性，体现继承思维，加入匿名结构体</span></span><br><span class="line">	Animal</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Cat绑定特有方法</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *Cat)</span></span> catShout() &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;喵~&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 创建Cat结构体实例</span></span><br><span class="line">	cat := &amp;Cat&#123;&#125;</span><br><span class="line">	cat.Age = <span class="number">3</span>				<span class="comment">// 原为cat.Animal.Age，已简化</span></span><br><span class="line">	cat.Weight = <span class="number">10.6</span></span><br><span class="line">	cat.ShowInfo()			<span class="comment">// 我的年龄是：3岁，体重是：10.6kg</span></span><br><span class="line">	cat.Shout()</span><br><span class="line">	cat.catShout()			<span class="comment">// 现在我要说话了：喵~</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="继承的特性"><a href="#继承的特性" class="headerlink" title="继承的特性"></a>继承的特性</h3><blockquote>
<p>就近访问原则</p>
</blockquote>
<p>当结构体和匿名结构体有相同的字段或者方法时，编译器采用就近访问原则，如果想要访问匿名结构体的字段或方法时，可以通过匿名结构体名来区分</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Animal <span class="keyword">struct</span> &#123;</span><br><span class="line">	Age <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(a *Animal)</span></span> f() &#123;</span><br><span class="line">	fmt.Printf(<span class="string">&quot;我是父类的方法~，Age：%v\n&quot;</span>, a.Age)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Cat <span class="keyword">struct</span> &#123;</span><br><span class="line">	Animal</span><br><span class="line">	Age <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *Cat)</span></span> f() &#123;</span><br><span class="line">	fmt.Printf(<span class="string">&quot;我是子类的方法~，Age：%v\n&quot;</span>, c.Age)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 创建Cat结构体实例</span></span><br><span class="line">	cat := &amp;Cat&#123;&#125;</span><br><span class="line">	cat.Age = <span class="number">3</span> <span class="comment">// 就近原则</span></span><br><span class="line">	cat.Animal.Age = <span class="number">6</span></span><br><span class="line">	cat.f() <span class="comment">// 就近原则</span></span><br><span class="line">	cat.Animal.f()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>多重继承</p>
</blockquote>
<p>Go语言中支持多继承，但为了保证代码的间接性，建议尽量不使用多重继承</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> A <span class="keyword">struct</span> &#123;</span><br><span class="line">	a <span class="type">int</span></span><br><span class="line">	b <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> B <span class="keyword">struct</span> &#123;</span><br><span class="line">	c <span class="type">int</span></span><br><span class="line">	d <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> C <span class="keyword">struct</span> &#123;</span><br><span class="line">	A</span><br><span class="line">	B</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	c := C&#123;A&#123;<span class="number">10</span>, <span class="string">&quot;aaa&quot;</span>&#125;, B&#123;<span class="number">20</span>, <span class="string">&quot;bbb&quot;</span>&#125;&#125;</span><br><span class="line">	fmt.Println(c)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h2><p> Go 语言的接口设计是<strong>非侵入式</strong>的，接口编写者无须知道接口被哪些类型实现，而接口的实现者只需知道实现的是什么样子的接口，但无须指明实现哪一个接口，因为编译器知道最终编译时使用哪个类型实现哪个接口，或者接口应该由谁来实现。</p>
<p>Go语言并不是一种 “传统” 的面向对象编程语言，它并没有类的概念，继承也是通过内嵌或组合来实现的，接口本身是调用方和实现方均需要遵守的一种协议，大家按照统一的方法命名参数类型和数量来协调逻辑处理的过程。</p>
<p>Go语言里有非常灵活的接口概念，通过它可以实现很多面向对象的特性，这种设计可以让你创建一个新的接口类型满足已经存在的具体类型却不会去改变这些类型的定义，当我们使用的类型来自于不受我们控制的包时这种设计尤其有用。</p>
<h3 id="接口的声明"><a href="#接口的声明" class="headerlink" title="接口的声明"></a>接口的声明</h3><p>接口是双方约定的一种合作协议。接口实现者不需要关心接口会被怎样使用，调用者也不需要关心接口的实现细节。接口是一种类型，也是一种抽象结构，不会暴露所含数据的格式、类型及结构。</p>
<ul>
<li>接口中可以定义一组方法，但不需要实现，不需要方法体。并且接口中不能包含任何变量。直到某个自定义类型要使用的时候，再根据具体情况把这些方法具体实现出来</li>
<li>实现接口要实现<strong>所有的方法</strong>才算是实现</li>
<li>Go语言中的接口，不需要显式的实现接口</li>
<li>接口的目的是为了定义规范，具体由别人来实现即可</li>
</ul>
<p><strong>接口声明格式如下</strong></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> 接口类型名 <span class="keyword">interface</span>&#123;</span><br><span class="line">    方法名<span class="number">1</span>( 参数列表<span class="number">1</span> ) 返回值列表<span class="number">1</span></span><br><span class="line">    方法名<span class="number">2</span>( 参数列表<span class="number">2</span> ) 返回值列表<span class="number">2</span></span><br><span class="line">    …</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>部分参数讲解</p>
<ul>
<li>接口类型名：使用 type 将接口定义为自定义的类型名。Go语言的接口在命名时，一般会在单词后面添加 er，如有写操作的接口叫 Writer，有字符串功能的接口叫 Stringer，有关闭功能的接口叫 Closer 等。</li>
<li>方法名：当方法名首字母是大写时，且这个接口类型名首字母也是大写时，这个方法可以被接口所在的包（package）之外的代码访问。</li>
<li>参数列表、返回值列表：参数列表和返回值列表中的参数变量名可以被忽略</li>
</ul>
<p>代码示例：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 接口的定义：定义规则、定义规范，定义某种能力</span></span><br><span class="line"><span class="keyword">type</span> AnimalSay <span class="keyword">interface</span> &#123;</span><br><span class="line">	<span class="comment">// 实现某种没有实现的方法</span></span><br><span class="line">	say()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 接口的实现</span></span><br><span class="line"><span class="keyword">type</span> Cat <span class="keyword">struct</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">type</span> Dog <span class="keyword">struct</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 实现接口的方法</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c Cat)</span></span> say() &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;喵~&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(d Dog)</span></span> say() &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;汪~&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义一个函数</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">shout</span><span class="params">(s AnimalSay)</span></span> &#123;</span><br><span class="line">	s.say()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	c := Cat&#123;&#125;</span><br><span class="line">	d := Dog&#123;&#125;</span><br><span class="line">	<span class="comment">// 猫叫</span></span><br><span class="line">	shout(c)</span><br><span class="line">	<span class="comment">// 狗叫</span></span><br><span class="line">	shout(d)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="接口的特性"><a href="#接口的特性" class="headerlink" title="接口的特性"></a>接口的特性</h3><ul>
<li>接口本身不能创建实例，但可以指向一个实现了该接口自定义类型的变量</li>
<li>只要是自定义数据类型，就可以实现接口，不仅仅是结构体类型</li>
<li>一个自定义类型可以实现很多接口</li>
<li>一个接口可以继承多个接口，如果这时要实现接口，那么必须将<strong>继承的几个接口方法全部实现</strong></li>
<li>interface类型默认是一个指针（引用类型），如果没有对interfce初始化就使用，那么将会输出空</li>
<li><strong>空接口没有任何方法，所以可以理解为所有类型都实现了空接口，也可以理解为我们可以把如何一个变量赋给空接口</strong></li>
</ul>
<h3 id="多态"><a href="#多态" class="headerlink" title="多态"></a>多态</h3><p>Go语言中的面向对象是抽象的，因此在Go语言中多态特征是<strong>通过接口实现的</strong>，可以按照统一的接口来调用不同的实现，这时接口变量就呈现出不同的形态</p>
<p>上方代码的这个函数，其中的<code>s</code>通过上下文来识别具体是什么类型的实例就完美体现了多态的表现</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">shout</span><span class="params">(s AnimalSay)</span></span> &#123;</span><br><span class="line">   s.say()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>接口体现多态特征</p>
</blockquote>
<ol>
<li><p>多态参数：其中的s就是多态参数</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">shout</span><span class="params">(s AnimalSay)</span></span> &#123;</span><br><span class="line">   s.say()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>多态数组：定义一个接口数组，里面存放各个结构体变量即可</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">var arr [3]AnimalSay</span><br><span class="line">arr[0] = Dog&#123;&quot;小狗1号&quot;&#125;</span><br><span class="line">arr[1] = Cat&#123;&quot;小猫1号&quot;&#125;</span><br><span class="line">arr[2] = Cat&#123;&quot;小猫2号&quot;&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<p><strong>如果有过其他语言中面向对象的基础应该很好理解，但对于纯小白来说还是推荐去看更详细的资料</strong></p>
<h3 id="断言"><a href="#断言" class="headerlink" title="断言"></a>断言</h3><p>类型断言（Type Assertion）是一个使用在接口值上的操作，用于检查接口类型变量所持有的值是否实现了期望的接口或者具体的类型，也就是直接<strong>判断是否是该类型的变量</strong>。</p>
<p>Go语言中类型断言的语法格式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">value, ok := x.(T)</span><br></pre></td></tr></table></figure>

<p>其中，x 表示一个接口的类型，T 表示一个具体的类型（也可为接口类型）。</p>
<p>该断言表达式会返回 x 的值（也就是 value）和一个布尔值（也就是 ok），可根据该布尔值判断 x 是否为 T 类型：</p>
<ul>
<li>如果 T 是具体某个类型，类型断言会检查 x 的动态类型是否等于具体类型 T。如果检查成功，类型断言返回的结果是 x 的动态值，其类型是 T。</li>
<li>如果 T 是接口类型，类型断言会检查 x 的动态类型是否满足 T。如果检查成功，x 的动态值不会被提取，返回值是一个类型为 T 的接口值。</li>
<li>无论 T 是什么类型，如果 x 是 nil 接口值，类型断言都会失败。</li>
</ul>
<p>代码示例：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 定义接口</span></span><br><span class="line">	<span class="keyword">var</span> x <span class="keyword">interface</span>&#123;&#125;</span><br><span class="line">	x = <span class="number">10</span></span><br><span class="line">	<span class="comment">// 断言：x是否能转成int类型并赋值给value，flag判断是否成功</span></span><br><span class="line">	value, flag := x.(<span class="type">int</span>)</span><br><span class="line">	fmt.Println(value, <span class="string">&quot;,&quot;</span>, flag)	<span class="comment">// 10 , true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>搭配switch使用</p>
</blockquote>
<p>类型断言还可以配合 switch 使用，示例代码如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="keyword">var</span> a <span class="type">int</span></span><br><span class="line">    a = <span class="number">10</span></span><br><span class="line">    getType(a)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">getType</span><span class="params">(a <span class="keyword">interface</span>&#123;&#125;)</span></span> &#123;</span><br><span class="line">    <span class="keyword">switch</span> a.(<span class="keyword">type</span>) &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="type">int</span>:</span><br><span class="line">        fmt.Println(<span class="string">&quot;the type of a is int&quot;</span>)</span><br><span class="line">    <span class="keyword">case</span> <span class="type">string</span>:</span><br><span class="line">        fmt.Println(<span class="string">&quot;the type of a is string&quot;</span>)</span><br><span class="line">    <span class="keyword">case</span> <span class="type">float64</span>:</span><br><span class="line">        fmt.Println(<span class="string">&quot;the type of a is float&quot;</span>)</span><br><span class="line">    <span class="keyword">default</span>:</span><br><span class="line">        fmt.Println(<span class="string">&quot;unknown type&quot;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<hr>
<h1 id="并发"><a href="#并发" class="headerlink" title="并发"></a>并发</h1><p>程序（program）：为了完成某种特定任务而编写的静态代码，程序是静态的，程序运行才产生了进程</p>
<p>进程（process）：程序的一次执行过程，每个进程都会在内存中有自己的内存区域，进程是动态的，它有自己的生命周期，有产生、存在、消亡的过程</p>
<p>线程（thread）：进程可以有多条线程，线程只是程序内部的一条执行路径</p>
<p>协程（goroutine ）：协程是一种用户态的轻量级线程，这里的协程和其他语言的协程（coroutine）不一样</p>
<p>管道（channel）：协程之间通信的桥梁，管道是双向的</p>
<p>并行（Concurrent）：多个线程交替操作同一个资源类</p>
<p>并发（Paralled）：多个线程同时操作多个资源类</p>
<p>死掉的程序只是存储器上的数据，活过来的程序就是进程，没错，进程是有生命的，他有自己的生命周期。</p>
<h2 id="协程"><a href="#协程" class="headerlink" title="协程"></a>协程</h2><p>Go主线程也可称为线程，也可以理解为进程，一个Go主线程上可以起多个协程，可以理解协程为轻量级的线程，资源消耗较小</p>
<p>协程的特点：有独立的栈空间、共享程度堆空间、调度由用户控制，是轻量级的线程（协程的本质是单线程）</p>
<p><strong>Go语言高并发的的特性就是基于协程</strong></p>
<h3 id="认识协程"><a href="#认识协程" class="headerlink" title="认识协程"></a>认识协程</h3><p>以下全部为知识点，有些枯燥，但看完后会更全面的的了解go语言的协程</p>
<blockquote>
<p>协程为什么比线程快</p>
</blockquote>
<p>协程是一种用户态的轻量级线程，协程的调度完全由用户控制。从技术的角度来说，“协程就是你可以暂停执行的函数”。</p>
<p>在协程的调度切换时，可以将寄存器上下文和栈保存到其他地方，在切回来的时候，恢复先前保存的寄存器上下文和栈，直接操作栈则基本没有内核切换的开销，可以不加锁的访问全局变量，所以上下文的切换非常快。</p>
<blockquote>
<p>协程和线程的区别</p>
</blockquote>
<p>一个线程可以多个协程，一个进程也可以单独拥有多个协程，线程进程都是同步机制，而协程则是异步。</p>
<p>协程能保留上一次调用时的状态，每次过程重入时，就相当于进入上一次调用的状态，线程是抢占式，而协程是非抢占式的，所以需要用户自己释放使用权来切换到其他协程，因此同一时间其实只有一个协程拥有运行权，相当于单线程的能力。</p>
<p>协程并不是取代线程，而且抽象于线程之上，线程是协程的资源，协程通过执行器(Interceptor) 来间接使用线程这个资源。</p>
<blockquote>
<p>goroutine 和 coroutine</p>
</blockquote>
<p>C#、python、Lua等语言都支持 coroutine 特性，两者虽然都可以将函数或者语句在独立的环境中运行，但go语言的goroutine支持并行执行，而coroutine始终顺序执行，goroutines 是通过通道来通信；而coroutines 通过让出和恢复操作来通信，goroutines 比 coroutines 更强大，也很容易从 coroutines 的逻辑复用到 goroutines。</p>
<p>狭义地说，goroutine 可能发生在多线程环境下，goroutine 无法控制自己获取高优先度支持；coroutine 始终发生在单线程，coroutine 程序需要主动交出控制权，宿主才能获得控制权并将控制权交给其他 coroutine。</p>
<p>goroutine 间使用 channel 通信，coroutine 使用 yield 和 resume 操作。</p>
<p>goroutine 属于抢占式任务处理，操作系统如果发现一个应用程序长时间大量地占用 CPU，那么用户有权终止这个任务。</p>
<h3 id="协程的开启"><a href="#协程的开启" class="headerlink" title="协程的开启"></a>协程的开启</h3><p>协程的开启十分简单，只需要在函数前面加上<code>go</code>关键字即可</p>
<p>协程是和主线程一同执行的</p>
<p>示例代码如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 主线程</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 开启协程</span></span><br><span class="line">	<span class="keyword">go</span> test()</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;我是主线程，执行了%v次\n&quot;</span>, i+<span class="number">1</span>)</span><br><span class="line">		<span class="comment">// 阻塞一秒</span></span><br><span class="line">		time.Sleep(time.Second)</span><br><span class="line">	&#125;</span><br><span class="line">	fmt.Printf(<span class="string">&quot;我是主线程，我要结束运行了&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">test</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;我是一个协程，执行了%v次\n&quot;</span>, i+<span class="number">1</span>)</span><br><span class="line">		<span class="comment">// 阻塞一秒</span></span><br><span class="line">		time.Sleep(time.Second)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>主死从随</p>
</blockquote>
<p>如果主线程结束了，即使协程还没有执行完毕，那么协程也会跟着退出，但协程结束了并不会影响主进程</p>
<p>代码示例：</p>
<p>上方代码的test函数更改为无限循环即可</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">test</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;我是一个协程，执行了%v次\n&quot;</span>, i+<span class="number">1</span>)</span><br><span class="line">		<span class="comment">// 阻塞一秒</span></span><br><span class="line">		time.Sleep(time.Second)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>匿名函数创建多个协程</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 匿名函数+外部变量 = 闭包</span></span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">6</span>; i++ &#123;</span><br><span class="line">		<span class="comment">// 启动一个协程</span></span><br><span class="line">		<span class="comment">// 使用匿名函数，直接调用匿名函数</span></span><br><span class="line">		<span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">(n <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">			fmt.Printf(<span class="string">&quot;我是第%v个协程\n&quot;</span>, n+<span class="number">1</span>)</span><br><span class="line">		&#125;(i)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 阻塞一秒</span></span><br><span class="line">	time.Sleep(time.Second)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;我是主线程，我要结束运行了&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="WaitGroup"><a href="#WaitGroup" class="headerlink" title="WaitGroup"></a>WaitGroup</h3><p>Go语言的WaitGroup是一种用于管理多个goroutine的工具，它可以帮助开发者确保所有goroutine都完成了任务，然后再继续执行下一步操作。简单来说就是控制协程的主死从随</p>
<p>WaitGroup的更多详情请查看Go语言中文标准库：<a target="_blank" rel="noopener" href="https://studygolang.com/pkgdoc">Go语言标准库</a></p>
<p>代码示例：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;sync&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义WaitGroup</span></span><br><span class="line"><span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 启动6个协程</span></span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">1</span>; i &lt; <span class="number">7</span>; i++ &#123;</span><br><span class="line">		wg.Add(<span class="number">1</span>) <span class="comment">// 协程开始时加1</span></span><br><span class="line">		<span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">(n <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">			<span class="keyword">defer</span> wg.Done() <span class="comment">// 协程执行完减1</span></span><br><span class="line">			fmt.Printf(<span class="string">&quot;你好，我是第%v个协程\n&quot;</span>, n)</span><br><span class="line">		&#125;(i)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 阻塞主线程，当wg减为0时，停止阻塞</span></span><br><span class="line">	wg.Wait()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="互斥锁"><a href="#互斥锁" class="headerlink" title="互斥锁"></a>互斥锁</h3><p>当协程操作同一个数据的时候会发生抢占资源的行为，导致数据结果不准确，这时，我们就需要互斥锁（Mutex）来解决这个问题（试试不加锁会出现什么（～￣▽￣～）），注：互斥锁性能、效率较低</p>
<p>Go语言的mutex（互斥锁）是一种用于在多个goroutine之间同步访问共享资源的机制。它可以防止多个goroutine同时访问共享资源，从而避免数据竞争。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;sync&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line"><span class="keyword">var</span> totalNum <span class="type">int</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 加入互斥锁</span></span><br><span class="line"><span class="keyword">var</span> lock sync.Mutex</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	wg.Add(<span class="number">2</span>)</span><br><span class="line">	<span class="keyword">go</span> add()</span><br><span class="line">	<span class="keyword">go</span> sub()</span><br><span class="line">	wg.Wait()</span><br><span class="line">	fmt.Println(totalNum)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">sub</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">defer</span> wg.Done()</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">1000</span>; i++ &#123;</span><br><span class="line">		<span class="comment">// 加锁</span></span><br><span class="line">		lock.Lock()</span><br><span class="line">		totalNum -= <span class="number">1</span></span><br><span class="line">		<span class="comment">// 解锁</span></span><br><span class="line">		lock.Unlock()</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">add</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">defer</span> wg.Done()</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">1000</span>; i++ &#123;</span><br><span class="line">		lock.Lock()</span><br><span class="line">		totalNum += <span class="number">1</span></span><br><span class="line">		lock.Unlock()</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="读写锁"><a href="#读写锁" class="headerlink" title="读写锁"></a>读写锁</h3><p>当我们遇到读多写少的场景时，由于读对数据不产生影响，所以推荐使用读写锁（RWMutex）</p>
<p>Go语言的RWMutex（读写锁）是一种同步机制，它可以同时允许多个读取操作，但只允许一个写入操作。它可以帮助程序员控制对共享资源的访问，以避免竞争条件和数据不一致的问题。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;sync&quot;</span></span><br><span class="line">	<span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line"></span><br><span class="line"><span class="comment">// 加入读写锁</span></span><br><span class="line"><span class="keyword">var</span> lock sync.RWMutex</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	wg.Add(<span class="number">6</span>)</span><br><span class="line">	<span class="comment">// 模拟读多写少</span></span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">5</span>; i++ &#123;</span><br><span class="line">		<span class="keyword">go</span> read()</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">go</span> write()</span><br><span class="line">	wg.Wait()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">read</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">defer</span> wg.Done()</span><br><span class="line">	lock.RLock() <span class="comment">// 如果只是读数据，这个锁不发挥作用，但读写同时发生时，锁就会发挥作用</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;开始读取数据&quot;</span>)</span><br><span class="line">	time.Sleep(time.Second)</span><br><span class="line">	fmt.Println(<span class="string">&quot;读取数据成功&quot;</span>)</span><br><span class="line">	lock.RUnlock()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">write</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">defer</span> wg.Done()</span><br><span class="line">	lock.Lock()</span><br><span class="line">	fmt.Println(<span class="string">&quot;开始修改数据&quot;</span>)</span><br><span class="line">	time.Sleep(time.Second * <span class="number">6</span>)</span><br><span class="line">	fmt.Println(<span class="string">&quot;修改数据成功&quot;</span>)</span><br><span class="line">	lock.Unlock()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="捕获错误"><a href="#捕获错误" class="headerlink" title="捕获错误"></a>捕获错误</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">go</span> printNum()</span><br><span class="line">	<span class="keyword">go</span> division()</span><br><span class="line">	time.Sleep(time.Second)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">division</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 捕获错误并处理</span></span><br><span class="line">	<span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">		err := <span class="built_in">recover</span>()</span><br><span class="line">		<span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">			fmt.Println(<span class="string">&quot;division函数出现错误&quot;</span>, err)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;()</span><br><span class="line">	num1 := <span class="number">10</span></span><br><span class="line">	num2 := <span class="number">0</span></span><br><span class="line">	result := num1 / num2</span><br><span class="line">	fmt.Println(result)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">printNum</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">6</span>; i++ &#123;</span><br><span class="line">		fmt.Println(i + <span class="number">1</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="管道"><a href="#管道" class="headerlink" title="管道"></a>管道</h2><p>简但来说管道（channel）是协程（goroutine ）之间的通信机制</p>
<p>管道的特性：</p>
<ul>
<li><p>管道可以实现多个goroutine之间的通信</p>
</li>
<li><p>管道可以实现数据的流动、缓冲、同步</p>
</li>
<li><p>管道可以实现数据的<strong>安全传输</strong></p>
</li>
</ul>
<p>管道的性质：</p>
<ul>
<li><p>管道的本质就是一个基于队列的数据结构，因此它的数据是<strong>先进先出</strong>的</p>
</li>
<li><p>管道自身线程安全，多协程访问时，不需要加锁，因为它本身就是线程安全的</p>
</li>
<li><p>管道有类型，一个固定类型的管道只能存放固定类型的数据</p>
</li>
</ul>
<p>Go语言的管道是一种编程模式，它可以让程序员将多个函数连接起来，每个函数处理输入数据，并将处理后的结果传递给下一个函数。管道可以让程序员更容易地处理复杂的数据处理任务，并且可以更快地完成任务。</p>
<h3 id="管道入门"><a href="#管道入门" class="headerlink" title="管道入门"></a>管道入门</h3><p>通道本身需要一个类型进行修饰，就像切片类型需要标识元素类型，通道的元素类型就是在其内部传输的数据类型</p>
<p>管道的声明方式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> 管道变量 <span class="keyword">chan</span> 管道类型</span><br></pre></td></tr></table></figure>

<p>管道是引用类型，它在内存里的值是一个地址，所以需要使用 make 进行创建，格式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">管道实例 := <span class="built_in">make</span>(<span class="keyword">chan</span> 数据类型)</span><br></pre></td></tr></table></figure>

<p>管道创建后，就可以使用<code>&lt;-</code>对通道进行发送和接收操作</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">管道变量 &lt;- 值</span><br></pre></td></tr></table></figure>

<p>代码示例：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 声明一个int类型的管道</span></span><br><span class="line">	<span class="keyword">var</span> intChan <span class="keyword">chan</span> <span class="type">int</span></span><br><span class="line">	<span class="comment">// make进行初始化：管道可以存放3个int类型的数据</span></span><br><span class="line">	intChan = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>, <span class="number">3</span>)</span><br><span class="line">	<span class="comment">// 存放数据</span></span><br><span class="line">	intChan &lt;- <span class="number">6</span></span><br><span class="line">	intChan &lt;- <span class="number">66</span></span><br><span class="line">	intChan &lt;- <span class="number">666</span></span><br><span class="line">	<span class="comment">// 从管道中读取数据</span></span><br><span class="line">	data1 := &lt;-intChan</span><br><span class="line">	data2 := &lt;-intChan</span><br><span class="line">	data3 := &lt;-intChan</span><br><span class="line">	fmt.Println(<span class="string">&quot;data1：&quot;</span>, data1)</span><br><span class="line">	fmt.Println(<span class="string">&quot;data2：&quot;</span>, data2)</span><br><span class="line">	fmt.Println(<span class="string">&quot;data3：&quot;</span>, data3)</span><br><span class="line">	<span class="comment">// 输出管道</span></span><br><span class="line">	fmt.Printf(<span class="string">&quot;管道的实际长度：%v，管道的容量是：%v&quot;</span>, <span class="built_in">len</span>(intChan), <span class="built_in">cap</span>(intChan))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>注意：</p>
<ul>
<li>管道不能存放大于容量的数据</li>
<li>如果接收方一直没有接收，那么发送操作将持续阻塞</li>
<li>在不使用协程的情况下，如果管道的数据已经全被取出，那么再取就会报错</li>
</ul>
<blockquote>
<p>管道的关闭</p>
</blockquote>
<p>内置函数close可以关闭管道，<strong>关闭后只能读取数据，但不能在写入数据</strong></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	intChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>, <span class="number">6</span>)</span><br><span class="line">	intChan &lt;- <span class="number">6</span></span><br><span class="line">	intChan &lt;- <span class="number">66</span></span><br><span class="line">	<span class="comment">// 关闭管道</span></span><br><span class="line">	<span class="built_in">close</span>(intChan)</span><br><span class="line">	<span class="comment">// 写入管道</span></span><br><span class="line">	<span class="comment">// intChan &lt;- 666 // 报错：send on closed channel</span></span><br><span class="line">	<span class="comment">// 读取管道</span></span><br><span class="line">	data := &lt;-intChan</span><br><span class="line">	<span class="built_in">println</span>(data)	<span class="comment">// 6</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>管道的遍历</p>
</blockquote>
<p>管道的遍历使用for-range遍历</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	intChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>, <span class="number">6</span>)</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">6</span>; i++ &#123;</span><br><span class="line">		intChan &lt;- i</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">close</span>(intChan)</span><br><span class="line">	<span class="comment">// 遍历</span></span><br><span class="line">	<span class="keyword">for</span> data := <span class="keyword">range</span> intChan &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;data =&quot;</span>, data)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="单向管道"><a href="#单向管道" class="headerlink" title="单向管道"></a>单向管道</h3><p>Go语言的类型系统提供了单方向的 channel 类型，顾名思义，单向 channel 就是只能用于写入或者只能用于读取数据。当然 channel 本身必然是同时支持读写的，否则根本没法用。</p>
<blockquote>
<p>单向管道的声明</p>
</blockquote>
<p>单向 channel 变量的声明非常简单，只能写入数据的通道类型为<code>chan&lt;-</code>，只能读取数据的通道类型为<code>&lt;-chan</code></p>
<p>单向管道的声明方式如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> 管道实例 <span class="keyword">chan</span> &lt;- 元素类型    <span class="comment">// 只能写入数据的通道</span></span><br><span class="line"><span class="keyword">var</span> 管道实例 &lt;- <span class="keyword">chan</span> 元素类型    <span class="comment">// 只能读取数据的通道</span></span><br></pre></td></tr></table></figure>

<p>代码示例：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 声明只写管道</span></span><br><span class="line">	<span class="keyword">var</span> ch1 <span class="keyword">chan</span>&lt;- <span class="type">int</span></span><br><span class="line">	ch1 = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>, <span class="number">6</span>)</span><br><span class="line">	ch1 &lt;- <span class="number">66</span></span><br><span class="line">	<span class="comment">//data1 := &lt;-ch	// 报错：cannot receive from send-only channel</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;ch1地址:&quot;</span>, ch1)</span><br><span class="line">	<span class="comment">// 声明只读管道</span></span><br><span class="line">	<span class="keyword">var</span> ch2 &lt;-<span class="keyword">chan</span> <span class="type">int</span></span><br><span class="line">	<span class="comment">// ch2 &lt;- 66	// 报错：cannot send to receive-only channel</span></span><br><span class="line">	<span class="keyword">if</span> ch2 != <span class="literal">nil</span> &#123;</span><br><span class="line">		data2 := &lt;-ch2</span><br><span class="line">		fmt.Println(<span class="string">&quot;data2:&quot;</span>, data2)</span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;ch2值为空&quot;</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="select"><a href="#select" class="headerlink" title="select"></a>select</h3><p>Go语言的select关键字用于多路复用，它可以同时监听多个通道的数据流动，当某个通道有数据流动时，就会进行处理。</p>
<p>select 的用法与 switch 语言非常类似，由 select 开始一个新的选择块，每个选择条件由 case 语句来描述，与 switch 语句相比，select 有比较多的限制，其中最大的一条限制就是每个 case 语句里必须是一个 IO 操作</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 定义int管道</span></span><br><span class="line">	intChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>, <span class="number">1</span>)</span><br><span class="line">	<span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">		time.Sleep(time.Second * <span class="number">6</span>)</span><br><span class="line">		intChan &lt;- <span class="number">6</span></span><br><span class="line">	&#125;()</span><br><span class="line">	<span class="comment">// 定义string管道</span></span><br><span class="line">	strChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">string</span>, <span class="number">1</span>)</span><br><span class="line">	<span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">		time.Sleep(time.Second)</span><br><span class="line">		strChan &lt;- <span class="string">&quot;玄德&quot;</span></span><br><span class="line">	&#125;()</span><br><span class="line">	<span class="keyword">select</span> &#123;</span><br><span class="line">	<span class="keyword">case</span> data := &lt;-intChan:</span><br><span class="line">		fmt.Println(<span class="string">&quot;intChan:&quot;</span>, data)</span><br><span class="line">	<span class="keyword">case</span> data := &lt;-strChan:</span><br><span class="line">		fmt.Println(<span class="string">&quot;strChan:&quot;</span>, data)</span><br><span class="line">	<span class="keyword">default</span>:</span><br><span class="line">		fmt.Println(<span class="string">&quot;防止select被阻塞&quot;</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="并发编程"><a href="#并发编程" class="headerlink" title="并发编程"></a>并发编程</h2><p>并发可以让多个任务同时运行，从而提高程序的效率，Go语言利用协程和管道可以轻松做到百万并发量，至于是不是真的百万并发我也不知道（～￣▽￣～）</p>
<h3 id="协程与管道"><a href="#协程与管道" class="headerlink" title="协程与管道"></a>协程与管道</h3><p>Go语言通过协程与管道可以实现复杂的并发编程，复习一下协程和管道吧</p>
<h4 id="操作同一个管道"><a href="#操作同一个管道" class="headerlink" title="操作同一个管道"></a>操作同一个管道</h4><blockquote>
<p>利用WaitGroup来阻塞</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;sync&quot;</span></span><br><span class="line">	<span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	wg.Add(<span class="number">2</span>)</span><br><span class="line">	intChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>, <span class="number">66</span>)</span><br><span class="line">	<span class="comment">// 开启读和写的协程，共同操作一个管道</span></span><br><span class="line">	<span class="keyword">go</span> writeData(intChan)</span><br><span class="line">	<span class="keyword">go</span> redaData(intChan)</span><br><span class="line">	<span class="comment">// 等待协程</span></span><br><span class="line">	wg.Wait()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 写</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">writeData</span><span class="params">(intChan <span class="keyword">chan</span> <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">    <span class="comment">// 在函数退出时调用Done 来通知main 函数工作已经完成</span></span><br><span class="line">	<span class="keyword">defer</span> wg.Done()</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">66</span>; i++ &#123;</span><br><span class="line">		intChan &lt;- i + <span class="number">1</span></span><br><span class="line">		fmt.Println(<span class="string">&quot;写入的数据为：&quot;</span>, i)</span><br><span class="line">		time.Sleep(time.Second)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">close</span>(intChan)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 读</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">redaData</span><span class="params">(intChan <span class="keyword">chan</span> <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">defer</span> wg.Done()</span><br><span class="line">	<span class="keyword">for</span> data := <span class="keyword">range</span> intChan &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;读取的数据为：&quot;</span>, data)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>利用管道来阻塞</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 声明被操作的管道</span></span><br><span class="line">	intChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>, <span class="number">66</span>)</span><br><span class="line">	<span class="comment">// 声明阻塞管道</span></span><br><span class="line">	exitChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">bool</span>, <span class="number">1</span>)</span><br><span class="line">	<span class="comment">// 开启读和写的协程，共同操作一个管道</span></span><br><span class="line">	<span class="keyword">go</span> writeData(intChan)</span><br><span class="line">	<span class="keyword">go</span> redaData(intChan, exitChan)</span><br><span class="line">	time.Sleep(time.Second)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;运行完毕&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 写</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">writeData</span><span class="params">(intChan <span class="keyword">chan</span> <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">66</span>; i++ &#123;</span><br><span class="line">		intChan &lt;- i + <span class="number">1</span></span><br><span class="line">		fmt.Println(<span class="string">&quot;写入的数据为：&quot;</span>, i+<span class="number">1</span>)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">close</span>(intChan)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 读</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">redaData</span><span class="params">(intChan <span class="keyword">chan</span> <span class="type">int</span>, exitChan <span class="keyword">chan</span> <span class="type">bool</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> data := <span class="keyword">range</span> intChan &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;读取的数据为：&quot;</span>, data)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 读取完毕</span></span><br><span class="line">	exitChan &lt;- <span class="literal">true</span></span><br><span class="line">	<span class="built_in">close</span>(exitChan)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="求素数"><a href="#求素数" class="headerlink" title="求素数"></a>求素数</h4><p>求10000以内的素数，利用协程试一试，在不用协程试一试，看看哪个更快&lt;（￣︶￣）&gt;</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> intChan = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>, <span class="number">10000</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">go</span> initChan(<span class="number">10000</span>)</span><br><span class="line">	<span class="keyword">var</span> primeChan = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>, <span class="number">10000</span>)</span><br><span class="line">	<span class="keyword">var</span> exitChan = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">bool</span>, <span class="number">8</span>)</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt;= <span class="number">8</span>; i++ &#123;</span><br><span class="line">		<span class="keyword">go</span> isPrime(intChan, primeChan, exitChan)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">		<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">8</span>; i++ &#123;</span><br><span class="line">			&lt;-exitChan</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="built_in">close</span>(primeChan)</span><br><span class="line">	&#125;()</span><br><span class="line">	<span class="keyword">for</span> res := <span class="keyword">range</span> primeChan &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;素数:&quot;</span>, res)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">initChan</span><span class="params">(num <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">1</span>; i &lt;= num; i++ &#123;</span><br><span class="line">		intChan &lt;- i</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">close</span>(intChan)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">isPrime</span><span class="params">(intChan &lt;-<span class="keyword">chan</span> <span class="type">int</span>, primeChan <span class="keyword">chan</span> <span class="type">int</span>, exitChan <span class="keyword">chan</span>&lt;- <span class="type">bool</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> flag <span class="type">bool</span></span><br><span class="line">	<span class="keyword">for</span> num := <span class="keyword">range</span> intChan &#123;</span><br><span class="line">		flag = <span class="literal">true</span></span><br><span class="line">		<span class="keyword">for</span> j := <span class="number">2</span>; j &lt; num; j++ &#123;</span><br><span class="line">			<span class="keyword">if</span> num%j == <span class="number">0</span> &#123;</span><br><span class="line">				flag = <span class="literal">false</span></span><br><span class="line">				<span class="keyword">continue</span></span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span> flag &#123;</span><br><span class="line">			primeChan &lt;- num</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	exitChan &lt;- <span class="literal">true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="生产者消费者"><a href="#生产者消费者" class="headerlink" title="生产者消费者"></a>生产者消费者</h3><p>通过协程和管道实现生产者消费者模型╮（￣▽￣）╭</p>
<p><img src="https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/3107/image-20230223234829972.png" alt="image-20230223234829972"></p>
<p>代码实现：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;strconv&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	storageChan := <span class="built_in">make</span>(<span class="keyword">chan</span> Product, <span class="number">1000</span>)</span><br><span class="line">	shopChan := <span class="built_in">make</span>(<span class="keyword">chan</span> Product, <span class="number">1000</span>)</span><br><span class="line">	exitChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">bool</span>, <span class="number">1</span>)</span><br><span class="line">	<span class="comment">// 协程生产</span></span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">999</span>; i++ &#123;</span><br><span class="line">		<span class="keyword">go</span> Producer(storageChan, <span class="number">1000</span>)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">go</span> Logistics(storageChan, shopChan)</span><br><span class="line">	<span class="keyword">go</span> Consumer(shopChan, <span class="number">1000</span>, exitChan)</span><br><span class="line">	<span class="keyword">if</span> &lt;-exitChan &#123;</span><br><span class="line">		<span class="keyword">return</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Product 商品</span></span><br><span class="line"><span class="keyword">type</span> Product <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Producer 生产者</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Producer</span><span class="params">(storageChan <span class="keyword">chan</span>&lt;- Product, count <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		producer := Product&#123;<span class="string">&quot;商品: &quot;</span> + strconv.Itoa(count)&#125;</span><br><span class="line">		storageChan &lt;- producer</span><br><span class="line">		count--</span><br><span class="line">		fmt.Println(<span class="string">&quot;生产了&quot;</span>, producer)</span><br><span class="line">		<span class="keyword">if</span> count &lt; <span class="number">1</span> &#123;</span><br><span class="line">			<span class="keyword">return</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Logistics 运输者</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Logistics</span><span class="params">(storageChan &lt;-<span class="keyword">chan</span> Product, shopChan <span class="keyword">chan</span>&lt;- Product)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		product := &lt;-storageChan</span><br><span class="line">		shopChan &lt;- product</span><br><span class="line">		fmt.Println(<span class="string">&quot;运输了&quot;</span>, product)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Consumer 消费者</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Consumer</span><span class="params">(shopChan &lt;-<span class="keyword">chan</span> Product, count <span class="type">int</span>, exitChan <span class="keyword">chan</span>&lt;- <span class="type">bool</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		product := &lt;-shopChan</span><br><span class="line">		fmt.Println(<span class="string">&quot;消费了&quot;</span>, product)</span><br><span class="line">		count--</span><br><span class="line">		<span class="keyword">if</span> count &lt; <span class="number">1</span> &#123;</span><br><span class="line">			exitChan &lt;- <span class="literal">true</span></span><br><span class="line">			<span class="keyword">return</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="网络编程"><a href="#网络编程" class="headerlink" title="网络编程"></a>网络编程</h2><p> Go语言里面提供了一个完善的 net&#x2F;http 包，通过 net&#x2F;http 包我们可以很方便的搭建一个可以运行的 Web 服务器。同时使用 net&#x2F;http 包能很简单地对 Web 的路由，静态文件，模版，cookie 等数据进行设置和操作。</p>
<h3 id="简单的Web服务器"><a href="#简单的Web服务器" class="headerlink" title="简单的Web服务器"></a>简单的Web服务器</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;log&quot;</span></span><br><span class="line">	<span class="string">&quot;net/http&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	http.HandleFunc(<span class="string">&quot;/&quot;</span>, index) <span class="comment">// index 为向 url发送请求时，调用的函数</span></span><br><span class="line">	log.Fatal(http.ListenAndServe(<span class="string">&quot;localhost:8080&quot;</span>, <span class="literal">nil</span>))</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">index</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">	fmt.Fprintf(w, <span class="string">&quot;玄德的网址：http://xuande-hk.gitee.io&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>浏览器访问localhost:8080，结果如下：</p>
<p><img src="https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/3107/image-20230218182229420.png" alt="image-20230218182229420"></p>
<h3 id="TCP网络协议通信"><a href="#TCP网络协议通信" class="headerlink" title="TCP网络协议通信"></a>TCP网络协议通信</h3><p>首先启动服务端，然后启动客户端</p>
<blockquote>
<p>客户端</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;bufio&quot;</span></span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;net&quot;</span></span><br><span class="line">	<span class="string">&quot;os&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;客户端启动中。。。。。。&quot;</span>)</span><br><span class="line">	<span class="comment">// 选择tcp协议，指定服务端ip和端口号</span></span><br><span class="line">	conn, err := net.Dial(<span class="string">&quot;tcp&quot;</span>, <span class="string">&quot;127.0.0.1:8888&quot;</span>)</span><br><span class="line">	<span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;客户端连接失败:&quot;</span>, err)</span><br><span class="line">		<span class="keyword">return</span></span><br><span class="line">	&#125;</span><br><span class="line">	fmt.Println(<span class="string">&quot;连接成功:&quot;</span>, conn)</span><br><span class="line">	<span class="comment">// 通过客户端发送数据</span></span><br><span class="line">	reader := bufio.NewReader(os.Stdin) <span class="comment">// os.Stdin表示终端标准输入</span></span><br><span class="line">	<span class="comment">// 从终端读取一行用户输入的信息</span></span><br><span class="line">	str, err := reader.ReadString(<span class="string">&#x27;\n&#x27;</span>)</span><br><span class="line">	<span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;终端输入失败:&quot;</span>, err)</span><br><span class="line">		<span class="keyword">return</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 将数据发送给服务器</span></span><br><span class="line">	write, err := conn.Write([]<span class="type">byte</span>(str))</span><br><span class="line">	<span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;数据发送失败:&quot;</span>, err)</span><br><span class="line">		<span class="keyword">return</span></span><br><span class="line">	&#125;</span><br><span class="line">	fmt.Printf(<span class="string">&quot;数据发送成功，共发送%d字节数据\n&quot;</span>, write)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;客户端结束连接。。。。。。&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>服务端</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;bufio&quot;</span></span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;net&quot;</span></span><br><span class="line">	<span class="string">&quot;os&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;服务端启动中。。。。。。&quot;</span>)</span><br><span class="line">	<span class="comment">// 监听客户端，同样需要选择tcp协议，指定服务端ip和端口号</span></span><br><span class="line">	listen, err := net.Listen(<span class="string">&quot;tcp&quot;</span>, <span class="string">&quot;127.0.0.1:8888&quot;</span>)</span><br><span class="line">	<span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;监听失败:&quot;</span>, err)</span><br><span class="line">		<span class="keyword">return</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 监听成功，等待客户端连接</span></span><br><span class="line">	fmt.Println(<span class="string">&quot;启动成功，等待客户端连接&quot;</span>)</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		conn, err2 := listen.Accept()</span><br><span class="line">		<span class="keyword">if</span> err2 != <span class="literal">nil</span> &#123;</span><br><span class="line">			fmt.Println(<span class="string">&quot;客户端连接失败:&quot;</span>, err)</span><br><span class="line">			<span class="keyword">return</span></span><br><span class="line">		&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">			fmt.Println(<span class="string">&quot;客户端连接成功:&quot;</span>, conn)</span><br><span class="line">			fmt.Println(<span class="string">&quot;客户端信息为:&quot;</span>, conn.RemoteAddr().String())</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">// 用协程处理客户端服务请求</span></span><br><span class="line">		<span class="keyword">go</span> process(conn)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">process</span><span class="params">(conn net.Conn)</span></span> &#123;</span><br><span class="line">	<span class="comment">// 关闭连接</span></span><br><span class="line">	<span class="keyword">defer</span> conn.Close()</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		<span class="comment">// 读取数据的切片</span></span><br><span class="line">		buf := <span class="built_in">make</span>([]<span class="type">byte</span>, <span class="number">1024</span>)</span><br><span class="line">		<span class="comment">// 从conn连接中读取数据</span></span><br><span class="line">		read, err := conn.Read(buf)</span><br><span class="line">		<span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">			<span class="keyword">return</span></span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">// 服务端输出</span></span><br><span class="line">		fmt.Println(<span class="string">&quot;接收到客户端数据:&quot;</span> + <span class="type">string</span>(buf[<span class="number">0</span>:read]))</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h1 id="反射"><a href="#反射" class="headerlink" title="反射"></a>反射</h1><p>Go语言中的反射是一种动态的编程技术，它允许程序在运行时获取有关自身结构和行为的信息，并可以根据这些信息动态地改变自身的行为。反射可以让程序更加灵活，可以更好地处理复杂的问题。</p>
<p>大多数现代的高级语言都以各种形式支持反射功能，反射是把双刃剑，功能强大但代码可读性并不理想，若非必要并不推荐使用反射。</p>
<h2 id="了解反射"><a href="#了解反射" class="headerlink" title="了解反射"></a>了解反射</h2><p>反射是指在程序运行期对程序本身进行访问和修改的能力。程序在编译时，变量被转换为内存地址，变量名不会被编译器写入到可执行部分。在运行程序时，程序无法获取自身的信息。</p>
<p>C&#x2F;C++ 语言没有支持反射功能，Lua、JavaScript 类动态语言因为其本身的语法特性并不需要反射，Java、C# 、Go等语言都支持完整的反射功能。</p>
<p>Go程序在运行期使用reflect包访问程序的反射信息。</p>
<ul>
<li>reflect.TypeOf（变量名），获取变量的类型，返回reflect.Type类型</li>
<li>reflect.ValueOf（变量名），获取变量的值，返回reflect.Value类型（结构体类型里面包含关于变量的信息）</li>
</ul>
<blockquote>
<p>反射可以做什么？</p>
</blockquote>
<ul>
<li>反射可以在运行时动态获取变量的各种信息，比如变量的类型，类别等信息</li>
<li>如果是结构体变量，还可以获取到结构体本身的信息（包括结构体的字段、方法）</li>
<li>通过反射，可以修改变量的值，可以调用关联的方法</li>
</ul>
<blockquote>
<p>反射的类型和种类</p>
</blockquote>
<p>在使用反射时，需要首先理解类型（Type）和种类（Kind）的区别。编程中，使用最多的是类型，但在反射中，当需要区分一个大品种的类型时，就会用到种类（Kind）。例如需要统一判断类型中的指针时，使用种类（Kind）信息就较为方便。</p>
<p>反射具体的方法请查看：<a target="_blank" rel="noopener" href="https://studygolang.com/pkgdoc">Go语言中文标准库</a>的reflect包</p>
<h2 id="反射的类型"><a href="#反射的类型" class="headerlink" title="反射的类型"></a>反射的类型</h2><p>Go语言程序中的类型（Type）指的是系统原生数据类型，如 int、string、bool、float32 等类型，以及使用 type 关键字定义的类型，这些类型的名称就是其类型本身的名称</p>
<blockquote>
<p>基本类型的反射</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;reflect&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> num = <span class="number">66</span></span><br><span class="line">	testReflect(num)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义一个空接口的函数</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testReflect</span><span class="params">(i <span class="keyword">interface</span>&#123;&#125;)</span></span> &#123;</span><br><span class="line">	<span class="comment">// 调用TypeOf函数，返回reflect.Type类型的数据</span></span><br><span class="line">	reType := reflect.TypeOf(i)</span><br><span class="line">	fmt.Println(<span class="string">&quot;reType:&quot;</span>, reType)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;reType的具体类型是:%T \n&quot;</span>, reType)</span><br><span class="line">	<span class="comment">// 调用ValueOf函数，返回reflect.Value类型的数据</span></span><br><span class="line">	reValue := reflect.ValueOf(i)</span><br><span class="line">	fmt.Println(<span class="string">&quot;reValue:&quot;</span>, reValue)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;reValue的具体类型是:%T&quot;</span>, reValue)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>结构体的反射</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;reflect&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// Student 学生结构体</span></span><br><span class="line"><span class="keyword">type</span> Student <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">	Age  <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	stu := Student&#123;</span><br><span class="line">		Name: <span class="string">&quot;玄德&quot;</span>,</span><br><span class="line">		Age:  <span class="number">20</span>,</span><br><span class="line">	&#125;</span><br><span class="line">	testReflect(stu)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义一个空接口的函数</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testReflect</span><span class="params">(i <span class="keyword">interface</span>&#123;&#125;)</span></span> &#123;</span><br><span class="line">	<span class="comment">// 调用TypeOf函数，返回reflect.Type类型的数据</span></span><br><span class="line">	reType := reflect.TypeOf(i)</span><br><span class="line">	fmt.Println(<span class="string">&quot;reType:&quot;</span>, reType)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;reType的具体类型是:%T \n&quot;</span>, reType)</span><br><span class="line">	<span class="comment">// 调用ValueOf函数，返回reflect.Value类型的数据</span></span><br><span class="line">	reValue := reflect.ValueOf(i)</span><br><span class="line">	fmt.Println(<span class="string">&quot;reValue:&quot;</span>, reValue)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;reValue的具体类型是:%T \n&quot;</span>, reValue)</span><br><span class="line"></span><br><span class="line">	<span class="comment">// reValue转为空接口</span></span><br><span class="line">	i2 := reValue.Interface()</span><br><span class="line">	<span class="comment">// 类型断言</span></span><br><span class="line">	n, flag := i2.(Student)</span><br><span class="line">	<span class="keyword">if</span> flag &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;学生的名字: %v\n学生的年龄：%v\n&quot;</span>, n.Name, n.Age)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="反射的种类"><a href="#反射的种类" class="headerlink" title="反射的种类"></a>反射的种类</h2><p>当需要区分一个大品种的类型时，就会用到种类（Kind）</p>
<p>Kind用于检查反射对象的类型，可以用来判断反射对象是否是指定的类型，以及反射对象的类型是什么。</p>
<blockquote>
<p>获取变量种类的两种方式</p>
</blockquote>
<ul>
<li>reflect.Type.Kind（）</li>
<li>reflect.Value.Kind（）</li>
</ul>
<p>种类（Kind）指的是对象归属的品种，在 reflect 包中有如下定义：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Kind <span class="type">uint</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> (</span><br><span class="line">    Invalid Kind = <span class="literal">iota</span>  <span class="comment">// 非法类型</span></span><br><span class="line">    Bool                 <span class="comment">// 布尔型</span></span><br><span class="line">    Int                  <span class="comment">// 有符号整型</span></span><br><span class="line">    Int8                 <span class="comment">// 有符号8位整型</span></span><br><span class="line">    Int16                <span class="comment">// 有符号16位整型</span></span><br><span class="line">    Int32                <span class="comment">// 有符号32位整型</span></span><br><span class="line">    Int64                <span class="comment">// 有符号64位整型</span></span><br><span class="line">    Uint                 <span class="comment">// 无符号整型</span></span><br><span class="line">    Uint8                <span class="comment">// 无符号8位整型</span></span><br><span class="line">    Uint16               <span class="comment">// 无符号16位整型</span></span><br><span class="line">    Uint32               <span class="comment">// 无符号32位整型</span></span><br><span class="line">    Uint64               <span class="comment">// 无符号64位整型</span></span><br><span class="line">    Uintptr              <span class="comment">// 指针</span></span><br><span class="line">    Float32              <span class="comment">// 单精度浮点数</span></span><br><span class="line">    Float64              <span class="comment">// 双精度浮点数</span></span><br><span class="line">    Complex64            <span class="comment">// 64位复数类型</span></span><br><span class="line">    Complex128           <span class="comment">// 128位复数类型</span></span><br><span class="line">    Array                <span class="comment">// 数组</span></span><br><span class="line">    Chan                 <span class="comment">// 通道</span></span><br><span class="line">    Func                 <span class="comment">// 函数</span></span><br><span class="line">    Interface            <span class="comment">// 接口</span></span><br><span class="line">    Map                  <span class="comment">// 映射</span></span><br><span class="line">    Ptr                  <span class="comment">// 指针</span></span><br><span class="line">    Slice                <span class="comment">// 切片</span></span><br><span class="line">    String               <span class="comment">// 字符串</span></span><br><span class="line">    Struct               <span class="comment">// 结构体</span></span><br><span class="line">    UnsafePointer        <span class="comment">// 底层指针</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure>

<p>代码示例：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;reflect&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// Student 学生结构体</span></span><br><span class="line"><span class="keyword">type</span> Student <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">	Age  <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	stu := Student&#123;</span><br><span class="line">		Name: <span class="string">&quot;玄德&quot;</span>,</span><br><span class="line">		Age:  <span class="number">20</span>,</span><br><span class="line">	&#125;</span><br><span class="line">	testReflect(stu)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义一个空接口的函数</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testReflect</span><span class="params">(i <span class="keyword">interface</span>&#123;&#125;)</span></span> &#123;</span><br><span class="line">	<span class="comment">// 调用TypeOf函数，返回reflect.Type类型的数据</span></span><br><span class="line">	reType := reflect.TypeOf(i)</span><br><span class="line">	fmt.Println(<span class="string">&quot;reType:&quot;</span>, reType)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;reType的具体类型是:%T \n&quot;</span>, reType)</span><br><span class="line">	<span class="comment">// 调用ValueOf函数，返回reflect.Value类型的数据</span></span><br><span class="line">	reValue := reflect.ValueOf(i)</span><br><span class="line">	fmt.Println(<span class="string">&quot;reValue:&quot;</span>, reValue)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;reValue的具体类型是:%T \n&quot;</span>, reValue)</span><br><span class="line">	<span class="comment">// 获取变量的类别</span></span><br><span class="line">	k1 := reType.Kind()</span><br><span class="line">	fmt.Println(k1)</span><br><span class="line">	k2 := reValue.Kind()</span><br><span class="line">	fmt.Println(k2)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="反射的操作"><a href="#反射的操作" class="headerlink" title="反射的操作"></a>反射的操作</h2><blockquote>
<p>反射操作时用到的函数</p>
</blockquote>
<ul>
<li>Elem（），值指向的元素值，类似于语言层<code>*</code>操作。当值类型不是指针或接口时发生宕 机，空指针时返回 nil 的 Value</li>
<li>Setlnt（x int64），使用 int64 设置值。当值的类型不是 int、int8、int16、 int32、int64 时会发生宕机</li>
</ul>
<blockquote>
<p>通过反射修改变量</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;reflect&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="comment">// 声明整型变量a并赋初值</span></span><br><span class="line">    <span class="keyword">var</span> a <span class="type">int</span> = <span class="number">66</span></span><br><span class="line">    <span class="comment">// 获取变量a的反射值对象(a的地址)</span></span><br><span class="line">    valueOfA := reflect.ValueOf(&amp;a)</span><br><span class="line">    <span class="comment">// 取出a地址的元素(a的值)</span></span><br><span class="line">    valueOfA = valueOfA.Elem()</span><br><span class="line">    <span class="comment">// 修改a的值为1</span></span><br><span class="line">    valueOfA.SetInt(<span class="number">666</span>)</span><br><span class="line">    <span class="comment">// 打印a的值</span></span><br><span class="line">    fmt.Println(valueOfA.Int())</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>通过反射修改结构体的值</p>
</blockquote>
<p>注：结构体成员中，如果字段没有被导出，即便不使用反射也可以被访问，但不能通过反射修改，因此为了能修改结构体的值，需要将该字段导出。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;reflect&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Cat <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">	Age  <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 定义结构体实例</span></span><br><span class="line">	cat := Cat&#123;Name: <span class="string">&quot;猫猫&quot;</span>, Age: <span class="number">0</span>&#125;</span><br><span class="line">	fmt.Printf(<span class="string">&quot;修改前的名字: %v \n&quot;</span>, cat.Name)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;修改前的年龄: %v \n&quot;</span>, cat.Age)</span><br><span class="line">	<span class="comment">// 获取Cat实例地址的反射值对象</span></span><br><span class="line">	valueOfCat := reflect.ValueOf(&amp;cat)</span><br><span class="line">	<span class="comment">// 取出cat实例地址的元素</span></span><br><span class="line">	valueOfCat = valueOfCat.Elem()</span><br><span class="line">	<span class="comment">// 获取并修改Name字段的值</span></span><br><span class="line">	valueOfCat.FieldByName(<span class="string">&quot;Name&quot;</span>).SetString(<span class="string">&quot;小猫&quot;</span>)</span><br><span class="line">	<span class="comment">// 获取Age字段的值</span></span><br><span class="line">	catAge := valueOfCat.FieldByName(<span class="string">&quot;Age&quot;</span>)</span><br><span class="line">	<span class="comment">// 尝试设置age的值(如果字段没有被导出，这里会发生崩溃)</span></span><br><span class="line">	catAge.SetInt(<span class="number">1</span>)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;修改后的名字: %v \n&quot;</span>, cat.Name)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;修改后的年龄: %v \n&quot;</span>, cat.Age)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>通过反射操作结构体属性和方法</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;reflect&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Cat <span class="keyword">struct</span> &#123;</span><br><span class="line">	Name <span class="type">string</span></span><br><span class="line">	Age  <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(cat Cat)</span></span> Test1() &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;这是第一个方法&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(cat Cat)</span></span> Test2() &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;这是第二个方法&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(cat Cat)</span></span> Test3(a <span class="type">int</span>, b <span class="type">int</span>) &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;这是第三个方法，这是一个求和方法&quot;</span>)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;%v + %v = %v&quot;</span>, a, b, a+b)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// 定义结构体实例</span></span><br><span class="line">	cat := Cat&#123;Name: <span class="string">&quot;猫猫&quot;</span>, Age: <span class="number">0</span>&#125;</span><br><span class="line">	<span class="comment">// 获取Cat实例的反射值对象</span></span><br><span class="line">	valueOfCat := reflect.ValueOf(cat)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;结构体实例反射值对象：%v \n&quot;</span>, valueOfCat)</span><br><span class="line">	<span class="comment">// 获取结构体内部的字段数量</span></span><br><span class="line">	field := valueOfCat.NumField()</span><br><span class="line">	fmt.Printf(<span class="string">&quot;结构体内部字段数量：%v \n&quot;</span>, field)</span><br><span class="line">	<span class="comment">// 获取具体字段</span></span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; field; i++ &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;第%d个字段的值是：%v \n&quot;</span>, i+<span class="number">1</span>, valueOfCat.Field(i))</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 获取结构体方法数量</span></span><br><span class="line">	method := valueOfCat.NumMethod()</span><br><span class="line">	fmt.Printf(<span class="string">&quot;结构体内部方法数量：%v \n&quot;</span>, method)</span><br><span class="line">	<span class="comment">// 调用Test2方法，方法首字母必须大写</span></span><br><span class="line">	valueOfCat.MethodByName(<span class="string">&quot;Test2&quot;</span>).Call(<span class="literal">nil</span>)</span><br><span class="line">	<span class="comment">// 调用Test3方法，传入参数</span></span><br><span class="line">	<span class="keyword">var</span> params []reflect.Value</span><br><span class="line">	params = <span class="built_in">append</span>(params, reflect.ValueOf(<span class="number">3</span>))</span><br><span class="line">	params = <span class="built_in">append</span>(params, reflect.ValueOf(<span class="number">3</span>))</span><br><span class="line">	valueOfCat.MethodByName(<span class="string">&quot;Test3&quot;</span>).Call(params)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>结果如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">结构体实例反射值对象：&#123;猫猫 <span class="number">0</span>&#125;</span><br><span class="line">结构体内部字段数量：<span class="number">2</span>           </span><br><span class="line">第<span class="number">1</span>个字段的值是：猫猫           </span><br><span class="line">第<span class="number">2</span>个字段的值是：<span class="number">0</span>              </span><br><span class="line">结构体内部方法数量：<span class="number">3</span>           </span><br><span class="line">这是第二个方法                  </span><br><span class="line">这是第三个方法，这是一个求和方法</span><br><span class="line"><span class="number">3</span> + <span class="number">3</span> = <span class="number">6</span>  </span><br></pre></td></tr></table></figure>



<h1 id="文件处理"><a href="#文件处理" class="headerlink" title="文件处理"></a>文件处理</h1><p>Go语言可以读写标准格式（如 XML 和 JSON 格式）的文件以及自定义的纯文本和二进制格式文件。现在我们可以灵活地使用 Go语言提供的所有工具，并利用闭包来避免重复性的代码，同时在某些情况下充分利用 Go语言对面向对象的支持，特别是对为函数添加方法的支持。</p>
<p>文件是保存数据的地方，是数据源的一种，比如txt文件、word、Excel、jpg等都是文件。文件最主要的作用就是保存数据。</p>
<p>其中Go语言内置的OS包下的File结构体封装了对文件的操作</p>
<p>Go语言中文标准库：<a target="_blank" rel="noopener" href="https://studygolang.com/pkgdoc">Go语言标准库</a></p>
<p>OpenFile文件打开模式Constants</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件</span><br><span class="line">O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件</span><br><span class="line">O_RDWR   int = syscall.O_RDWR   // 读写模式打开文件</span><br><span class="line">O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部</span><br><span class="line">O_CREATE int = syscall.O_CREAT  // 如果不存在将创建一个新文件</span><br><span class="line">O_EXCL   int = syscall.O_EXCL   // 和O_CREATE配合使用，文件必须不存在</span><br><span class="line">O_SYNC   int = syscall.O_SYNC   // 打开文件用于同步I/O</span><br><span class="line">O_TRUNC  int = syscall.O_TRUNC  // 如果可能，打开时清空文件</span><br></pre></td></tr></table></figure>

<p>权限控制（linux&#x2F;unix系统生效，windows下设置无效，windows放入0666即可）</p>
<h2 id="文本文件"><a href="#文本文件" class="headerlink" title="文本文件"></a>文本文件</h2><p>对文本文件操作，离不开IO流，IO流是程序和数据源之间沟通的桥梁，可以比喻为程序和数据源之间的一条水管，一点一点的流过去</p>
<blockquote>
<p>写纯文本文件</p>
</blockquote>
<p>由于Go语言的 fmt 包中打印函数强大而灵活，写纯文本数据非常简单直接，示例代码如下所示：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;bufio&quot;</span></span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;os&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">//创建一个新文件，写入内容</span></span><br><span class="line">	filePath := <span class="string">&quot;./output.txt&quot;</span></span><br><span class="line">    <span class="comment">// 更改OpenFile参数可以调整只读、只写、读写、追加模式</span></span><br><span class="line">	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, <span class="number">0666</span>)</span><br><span class="line">	<span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;打开文件错误= %v \n&quot;</span>, err)</span><br><span class="line">		<span class="keyword">return</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//及时关闭</span></span><br><span class="line">	<span class="keyword">defer</span> file.Close()</span><br><span class="line">	<span class="comment">//写入内容</span></span><br><span class="line">	str := <span class="string">&quot;你好，我是玄德\n&quot;</span> <span class="comment">// \n\r表示换行  txt文件要看到换行效果要用 \r\n</span></span><br><span class="line">	<span class="comment">//写入时，使用带缓存的 *Writer</span></span><br><span class="line">	writer := bufio.NewWriter(file)</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">3</span>; i++ &#123;</span><br><span class="line">		writer.WriteString(str)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//因为 writer 是带缓存的，因此在调用 WriterString 方法时，内容是先写入缓存的</span></span><br><span class="line">	<span class="comment">//所以要调用 flush方法，将缓存的数据真正写入到文件中。</span></span><br><span class="line">	writer.Flush()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>读纯文本文件</p>
</blockquote>
<p>打开并读取一个纯文本格式的数据跟写入纯文本格式数据一样简单。要解析文本来重建原始数据可能稍微复杂，这需根据格式的复杂性而定。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;bufio&quot;</span></span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;io&quot;</span></span><br><span class="line">	<span class="string">&quot;os&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">   <span class="comment">//打开文件</span></span><br><span class="line">   file, err := os.Open(<span class="string">&quot;./output.txt&quot;</span>)</span><br><span class="line">   <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">      fmt.Println(<span class="string">&quot;文件打开失败 = &quot;</span>, err)</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">//及时关闭 file 句柄，否则会有内存泄漏</span></span><br><span class="line">   <span class="keyword">defer</span> file.Close()</span><br><span class="line">   <span class="comment">//创建一个 *Reader ， 是带缓冲的，缓冲区：4096字节</span></span><br><span class="line">   reader := bufio.NewReader(file)</span><br><span class="line">   <span class="keyword">for</span> &#123;</span><br><span class="line">      str, err := reader.ReadString(<span class="string">&#x27;\n&#x27;</span>) <span class="comment">//读到一个换行就结束</span></span><br><span class="line">      <span class="keyword">if</span> err == io.EOF &#123;                  <span class="comment">//io.EOF 表示文件的末尾</span></span><br><span class="line">         <span class="keyword">break</span></span><br><span class="line">      &#125;</span><br><span class="line">      fmt.Print(str)</span><br><span class="line">   &#125;</span><br><span class="line">   fmt.Println(<span class="string">&quot;文件读取结束...&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>复制文件</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;io/ioutil&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	file1Path := <span class="string">&quot;./output.txt&quot;</span></span><br><span class="line">	file2Path := <span class="string">&quot;./output2.txt&quot;</span></span><br><span class="line">	data, err := ioutil.ReadFile(file1Path)</span><br><span class="line">	<span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;文件打开失败=%v\n&quot;</span>, err)</span><br><span class="line">		<span class="keyword">return</span></span><br><span class="line">	&#125;</span><br><span class="line">	err = ioutil.WriteFile(file2Path, data, <span class="number">0666</span>)</span><br><span class="line">	<span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">		fmt.Printf(<span class="string">&quot;文件打开失败=%v\n&quot;</span>, err)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h1 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h1><p><strong style="color:red">我们都是站在巨人的肩膀上，感谢所有愿意分享知识的人</strong></p>
<p>参考名单：</p>
<ul>
<li>感谢狂神的Go语言基础：<a target="_blank" rel="noopener" href="https://space.bilibili.com/95256449">狂神b站地址</a></li>
<li>感谢C语言中文网严站长：<a target="_blank" rel="noopener" href="http://c.biancheng.net/">C语言中文网</a></li>
<li>感谢马士兵教育珊珊老师：<a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1tP4y1v7kW/">b站珊珊老师</a></li>
<li>感谢马士兵教育申专老师：<a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1tP4y1v7kW/">b站申专老师</a></li>
<li>感谢ChatGPT语言模型：<a target="_blank" rel="noopener" href="https://chat.openai.com/chat">ChatGPT官网</a></li>
</ul>
<p><strong>颜文字：</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;（￣︶￣）&gt;	&lt;（￣︶￣）/ \（￣︶￣）/	╰（￣▽￣）╭	（╯－_－）╯╧╧	</span><br><span class="line">╮（￣▽￣）╭	（～￣▽￣～）╮(￣▽￣&quot;)╭	( ￣^￣)︵θ︵θ︵θ︵θ︵☆（&gt;口&lt;－）</span><br></pre></td></tr></table></figure>

<p><a href="#%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95">点击回到顶部（～￣▽￣～）</a></p>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="reward-container">
  <div>坚持原创技术分享，感谢您的支持和鼓励</div>
  <button>
    赞赏
  </button>
  <div class="post-reward">
      <div>
        <img src="/images/wechatpay.png" alt="玄德 微信">
        <span>微信</span>
      </div>
      <div>
        <img src="/images/alipay.png" alt="玄德 支付宝">
        <span>支付宝</span>
      </div>

  </div>
</div>

          <div class="followme">
  <span>欢迎关注我的其它发布渠道</span>

  <div class="social-list">

      <div class="social-item">
        <a target="_blank" class="social-link" href="/images/wechat_channel.jpg">
          <span class="icon">
            <i class="fab fa-weixin"></i>
          </span>

          <span class="label">WeChat</span>
        </a>
      </div>
  </div>
</div>

          <div class="post-tags">
              <a href="/tags/Go/" rel="tag"># Go</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/posts/4.html" rel="prev" title="Git学习笔记">
                  <i class="fa fa-chevron-left"></i> Git学习笔记
                </a>
            </div>
            <div class="post-nav-item">
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 2022 – 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">玄德</span>
</div>
<div class="busuanzi-count">
    <span class="post-meta-item" id="busuanzi_container_site_uv">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="我的第 undefined 位朋友，">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-item" id="busuanzi_container_site_pv">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="历经 undefined 次回眸才与你相遇">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>

    </div>
  </footer>

  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script>

  
<script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.0/search.js" integrity="sha256-vXZMYLEqsROAXkEw93GGIvaB2ab+QW6w3+1ahD9nXXA=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/pace.js"></script>

  
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>






  <script async src="/js/cursor/love.min.js"></script>


</body>
</html>
